diff mbox series

[LEDE-DEV,v2] ipq806x: add kernel 4.14 support

Message ID 1525451253-14562-1-git-send-email-rjangir@codeaurora.org
State Accepted
Headers show
Series [LEDE-DEV,v2] ipq806x: add kernel 4.14 support | expand

Commit Message

Ram Chandra Jangir May 4, 2018, 4:27 p.m. UTC
- Rebased the patches for 4.14
 - Dropped spi-qup and 0027, 0028, 0029
   clk patches since it's already included
   in upstream.

 Tested on IPQ AP148 Board:
  1) NOR boot and NAND boot
  2) Tested USB and PCIe interfaces
  3) WDOG test
  4) cpu frequency scaling
  5) ethernet, 2G and 5G WiFi
  6) ubi sysupgrade

Signed-off-by: Ram Chandra Jangir <rjangir@codeaurora.org>
---
Changes since v1:
 Fixes PCIe ext reset for IPQ8065 boards

 target/linux/ipq806x/config-4.14                   |   502 +
 .../arch/arm/boot/dts/qcom-ipq8064-ap148.dts       |   250 +
 .../arch/arm/boot/dts/qcom-ipq8064-c2600.dts       |   500 +
 .../arch/arm/boot/dts/qcom-ipq8064-d7800.dts       |   419 +
 .../arch/arm/boot/dts/qcom-ipq8064-db149.dts       |   236 +
 .../arch/arm/boot/dts/qcom-ipq8064-ea8500.dts      |   406 +
 .../arch/arm/boot/dts/qcom-ipq8064-r7500.dts       |   394 +
 .../arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts     |   425 +
 .../arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts     |   424 +
 .../arch/arm/boot/dts/qcom-ipq8064-wpq864.dts      |   570 +
 .../files-4.14/arch/arm/boot/dts/qcom-ipq8064.dtsi |  1333 +++
 .../arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts     |   393 +
 .../arch/arm/boot/dts/qcom-ipq8065-r7800.dts       |   575 +
 .../arch/arm/boot/dts/qcom-ipq8065-v1.0.dtsi       |     1 +
 .../files-4.14/arch/arm/boot/dts/qcom-ipq8065.dtsi |   164 +
 ...tbindings-qcom_adm-Fix-channel-specifiers.patch |    71 +
 .../0002-dmaengine-Add-ADM-driver.patch            |   966 ++
 .../0030-clk-Disable-i2c-device-on-gsbi4.patch     |    40 +
 ...31-mtd-add-SMEM-parser-for-QCOM-platforms.patch |   282 +
 .../patches-4.14/0032-phy-add-qcom-dwc3-phy.patch  |   616 ++
 ...tomatically-select-PCI_DOMAINS-if-PCI-is-.patch |    28 +
 ...-Add-Krait-L2-register-accessor-functions.patch |   147 +
 ...ux-Split-out-register-accessors-for-reuse.patch |   195 +
 ...dd-support-for-High-Frequency-PLLs-HFPLLs.patch |   352 +
 .../0039-clk-qcom-Add-HFPLL-driver.patch           |   206 +
 .../0040-clk-qcom-Add-IPQ806X-s-HFPLLs.patch       |   129 +
 ...041-clk-qcom-Add-support-for-Krait-clocks.patch |   241 +
 .../0042-clk-qcom-Add-KPSS-ACC-GCC-driver.patch    |   209 +
 ...lk-qcom-Add-Krait-clock-controller-driver.patch |   436 +
 .../0044-clk-Add-safe-switch-hook.patch            |   160 +
 ...-module-to-register-cpufreq-on-Krait-CPUs.patch |   307 +
 ...0046-cpufreq-qcom-independent-core-clocks.patch |    65 +
 ...eate-a-BBT-flag-to-access-bad-block-marke.patch |    72 +
 ...K-Allow-to-set-regulator-without-opp_list.patch |    26 +
 ...Support-adjusting-OPP-voltages-at-runtime.patch |   147 +
 ...a-helper-to-get-an-opp-regulator-for-devi.patch |    51 +
 ...te-the-voltage-tolerance-when-adjusting-t.patch |    38 +
 .../0053-regulator-add-smb208-support.patch        |    55 +
 ...ufreq-dt-Handle-OPP-voltage-adjust-events.patch |   131 +
 ...ufreq-dt-Add-L2-frequency-scaling-support.patch |    90 +
 .../0056-cpufreq-dt-Add-missing-rcu-locks.patch    |    23 +
 ...cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch |    29 +
 ...HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch |    62 +
 ...otfs-conflicts-with-OpenWrt-auto-mounting.patch |    23 +
 ...c-Added-the-enable-regs-and-mask-for-PRNG.patch |    25 +
 .../patches-4.14/0063-1-ipq806x-tsens-driver.patch |   627 ++
 ...3-2-tsens-support-configurable-interrupts.patch |   453 +
 .../patches-4.14/0064-clk-clk-rpm-fixes.patch      |    93 +
 .../0065-arm-override-compiler-flags.patch         |    21 +
 .../0066-GPIO-add-named-gpio-exports.patch         |   166 +
 ...eric-Mangle-bootloader-s-kernel-arguments.patch |   189 +
 .../patches-4.14/0069-arm-boot-add-dts-files.patch |    28 +
 .../0070-qcom-spm-fix-probe-order.patch            |    16 +
 ...-1-PCI-qcom-Fixed-IPQ806x-specific-clocks.patch |    95 +
 ...PCI-qcom-Fixed-IPQ806x-PCIE-reset-changes.patch |    85 +
 ...-PCI-qcom-Fixed-IPQ806x-PCIE-init-changes.patch |   126 +
 ...com-Programming-the-PCIE-iATU-for-IPQ806x.patch |   114 +
 .../0071-6-PCI-qcom-Force-GEN1-support.patch       |    61 +
 ...0071-7-pcie-Set-PCIE-MRRS-and-MPS-to-256B.patch |    69 +
 ...pcie-qcom-Fixed-pcie_phy_clk-branch-issue.patch |    91 +
 ...m-change-duplicate-pci-reset-to-phy-reset.patch |    25 +
 .../0072-add-ipq806x-with-no-clocks.patch          |    12 +
 ...om-use-scm_call-to-route-GPIO-irq-to-Apps.patch |   183 +
 ...0074-ipq806x-usb-Control-USB-master-reset.patch |    71 +
 ...td-nand-add-Winbond-manufacturer-and-chip.patch |    38 +
 .../patches-4.14/105-mtd-nor-add-mx25l25635f.patch |    22 +
 .../patches-4.14/310-msm-adhoc-bus-support.patch   | 11026 +++++++++++++++++++
 .../patches-4.14/850-soc-add-qualcomm-syscon.patch |   177 +
 68 files changed, 25602 insertions(+)
 create mode 100644 target/linux/ipq806x/config-4.14
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-c2600.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-d7800.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-db149.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-r7500.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064.dtsi
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-r7800.dts
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-v1.0.dtsi
 create mode 100644 target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065.dtsi
 create mode 100644 target/linux/ipq806x/patches-4.14/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0002-dmaengine-Add-ADM-driver.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0030-clk-Disable-i2c-device-on-gsbi4.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0032-phy-add-qcom-dwc3-phy.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0034-ARM-Add-Krait-L2-register-accessor-functions.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0035-clk-mux-Split-out-register-accessors-for-reuse.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0038-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0039-clk-qcom-Add-HFPLL-driver.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0040-clk-qcom-Add-IPQ806X-s-HFPLLs.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0041-clk-qcom-Add-support-for-Krait-clocks.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0042-clk-qcom-Add-KPSS-ACC-GCC-driver.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0043-clk-qcom-Add-Krait-clock-controller-driver.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0044-clk-Add-safe-switch-hook.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0045-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0046-cpufreq-qcom-independent-core-clocks.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0047-mtd-nand-Create-a-BBT-flag-to-access-bad-block-marke.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0048-PM-OPP-HACK-Allow-to-set-regulator-without-opp_list.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0053-regulator-add-smb208-support.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0056-cpufreq-dt-Add-missing-rcu-locks.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0062-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0063-1-ipq806x-tsens-driver.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0063-2-tsens-support-configurable-interrupts.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0064-clk-clk-rpm-fixes.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0065-arm-override-compiler-flags.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0066-GPIO-add-named-gpio-exports.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0067-generic-Mangle-bootloader-s-kernel-arguments.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0069-arm-boot-add-dts-files.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0070-qcom-spm-fix-probe-order.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0071-1-PCI-qcom-Fixed-IPQ806x-specific-clocks.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0071-2-PCI-qcom-Fixed-IPQ806x-PCIE-reset-changes.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0071-3-PCI-qcom-Fixed-IPQ806x-PCIE-init-changes.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0071-5-PCI-qcom-Programming-the-PCIE-iATU-for-IPQ806x.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0071-6-PCI-qcom-Force-GEN1-support.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0071-7-pcie-Set-PCIE-MRRS-and-MPS-to-256B.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0071-8-pcie-qcom-Fixed-pcie_phy_clk-branch-issue.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0071-9-pcie-qcom-change-duplicate-pci-reset-to-phy-reset.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0072-add-ipq806x-with-no-clocks.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0073-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/0074-ipq806x-usb-Control-USB-master-reset.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/104-mtd-nand-add-Winbond-manufacturer-and-chip.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/105-mtd-nor-add-mx25l25635f.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/310-msm-adhoc-bus-support.patch
 create mode 100644 target/linux/ipq806x/patches-4.14/850-soc-add-qualcomm-syscon.patch

Comments

Ram Chandra Jangir May 17, 2018, 11:47 a.m. UTC | #1
Thanks  Michael for confirming this,

Can you please help to update the kernel partition size to 4MB for R7800 and send it as patch to community (lede-dev@lists.infradead.org)?
This will help to enable kernel v4.14 for all ipq806x based boards.

John,
I do not have d7800, r7500, r7500v2 & vr2600v and hence seeking help to update partition size for these boards.

Thanks,
Ram

-----Original Message-----
From: Michael Yartys [mailto:michael.yartys@protonmail.com] 
Sent: Saturday, May 05, 2018 2:26 AM
To: Stefan Lippers-Hollmann <s.l-h@gmx.de>
Cc: Ram Chandra Jangir <rjangir@codeaurora.org>; msm-oss@mcclintock.net; lede-dev@lists.infradead.org; naresh@codeaurora.org
Subject: Re: [LEDE-DEV] [PATCH v2] ipq806x: add kernel 4.14 support

Hi

Can confirm that this works on my NETGEAR R7800 (ipq8065). The WLAN PCIe issues have been fixed.

I've also included my dmesg output in the attachment.

Thanks a lot for the help, Ram!

Michael

On 4 May 2018 9:40 PM, Stefan Lippers-Hollmann <s.l-h@gmx.de> wrote:

> Hi
> 
> On 2018-05-04, Ram Chandra Jangir wrote:
> 
> > -   Rebased the patches for 4.14
> > -   Dropped spi-qup and 0027, 0028, 0029
> >     
> >     clk patches since it's already included
> >     
> >     in upstream.
> >     
> > 
> > Tested on IPQ AP148 Board:
> > 
> > 1.  NOR boot and NAND boot
> > 2.  Tested USB and PCIe interfaces
> > 3.  WDOG test
> > 4.  cpu frequency scaling
> > 5.  ethernet, 2G and 5G WiFi
> > 6.  ubi sysupgrade
> > 
> > Signed-off-by: Ram Chandra Jangir rjangir@codeaurora.org
> > --------------------------------------------------------
> > 
> > Changes since v1:
> > 
> > Fixes PCIe ext reset for IPQ8065 boards
> 
> With these changes my ZyXEL nbg6817 (ipq8065) works fine (PCIe and
> 
> wlan), thanks a lot!
> 
> New, working, gzip compressed dmesg, attached.
> 
> Regards
> 
> Stefan Lippers-Hollmann
> 
> Lede-dev mailing list
> 
> Lede-dev@lists.infradead.org
> 
> http://lists.infradead.org/mailman/listinfo/lede-dev
John Crispin May 17, 2018, 1:56 p.m. UTC | #2
On 17/05/18 13:47, Ram Chandra Jangir wrote:
> Thanks  Michael for confirming this,
>
> Can you please help to update the kernel partition size to 4MB for R7800 and send it as patch to community (lede-dev@lists.infradead.org)?
> This will help to enable kernel v4.14 for all ipq806x based boards.

hang on, that would break sysupgrade or not ?

     John
>
> John,
> I do not have d7800, r7500, r7500v2 & vr2600v and hence seeking help to update partition size for these boards.
>
> Thanks,
> Ram
>
> -----Original Message-----
> From: Michael Yartys [mailto:michael.yartys@protonmail.com]
> Sent: Saturday, May 05, 2018 2:26 AM
> To: Stefan Lippers-Hollmann <s.l-h@gmx.de>
> Cc: Ram Chandra Jangir <rjangir@codeaurora.org>; msm-oss@mcclintock.net; lede-dev@lists.infradead.org; naresh@codeaurora.org
> Subject: Re: [LEDE-DEV] [PATCH v2] ipq806x: add kernel 4.14 support
>
> Hi
>
> Can confirm that this works on my NETGEAR R7800 (ipq8065). The WLAN PCIe issues have been fixed.
>
> I've also included my dmesg output in the attachment.
>
> Thanks a lot for the help, Ram!
>
> Michael
>
> On 4 May 2018 9:40 PM, Stefan Lippers-Hollmann <s.l-h@gmx.de> wrote:
>
>> Hi
>>
>> On 2018-05-04, Ram Chandra Jangir wrote:
>>
>>> -   Rebased the patches for 4.14
>>> -   Dropped spi-qup and 0027, 0028, 0029
>>>      
>>>      clk patches since it's already included
>>>      
>>>      in upstream.
>>>      
>>>
>>> Tested on IPQ AP148 Board:
>>>
>>> 1.  NOR boot and NAND boot
>>> 2.  Tested USB and PCIe interfaces
>>> 3.  WDOG test
>>> 4.  cpu frequency scaling
>>> 5.  ethernet, 2G and 5G WiFi
>>> 6.  ubi sysupgrade
>>>
>>> Signed-off-by: Ram Chandra Jangir rjangir@codeaurora.org
>>> --------------------------------------------------------
>>>
>>> Changes since v1:
>>>
>>> Fixes PCIe ext reset for IPQ8065 boards
>> With these changes my ZyXEL nbg6817 (ipq8065) works fine (PCIe and
>>
>> wlan), thanks a lot!
>>
>> New, working, gzip compressed dmesg, attached.
>>
>> Regards
>>
>> Stefan Lippers-Hollmann
>>
>> Lede-dev mailing list
>>
>> Lede-dev@lists.infradead.org
>>
>> http://lists.infradead.org/mailman/listinfo/lede-dev
>
>
>
> _______________________________________________
> Lede-dev mailing list
> Lede-dev@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/lede-dev
Michael Yartys via Lede-dev May 17, 2018, 2:04 p.m. UTC | #3
The sender domain has a DMARC Reject/Quarantine policy which disallows
sending mailing list messages using the original "From" header.

To mitigate this problem, the original message has been wrapped
automatically by the mailing list software.
‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐

On 17 May 2018 3:56 PM, John Crispin <john@phrozen.org> wrote:

> On 17/05/18 13:47, Ram Chandra Jangir wrote:
> 
> > Thanks Michael for confirming this,
> > 
> > Can you please help to update the kernel partition size to 4MB for R7800 and send it as patch to community (lede-dev@lists.infradead.org)?
> > 
> > This will help to enable kernel v4.14 for all ipq806x based boards.
> 
> hang on, that would break sysupgrade or not ?

Yes, it would.

> 
>     John
> 
> > John,
> > 
> > I do not have d7800, r7500, r7500v2 & vr2600v and hence seeking help to update partition size for these boards.
> > 
> > Thanks,
> > 
> > Ram
> > 
> > -----Original Message-----
> > 
> > From: Michael Yartys [mailto:michael.yartys@protonmail.com]
> > 
> > Sent: Saturday, May 05, 2018 2:26 AM
> > 
> > To: Stefan Lippers-Hollmann s.l-h@gmx.de
> > 
> > Cc: Ram Chandra Jangir rjangir@codeaurora.org; msm-oss@mcclintock.net; lede-dev@lists.infradead.org; naresh@codeaurora.org
> > 
> > Subject: Re: [LEDE-DEV] [PATCH v2] ipq806x: add kernel 4.14 support
> > 
> > Hi
> > 
> > Can confirm that this works on my NETGEAR R7800 (ipq8065). The WLAN PCIe issues have been fixed.
> > 
> > I've also included my dmesg output in the attachment.
> > 
> > Thanks a lot for the help, Ram!
> > 
> > Michael
> > 
> > On 4 May 2018 9:40 PM, Stefan Lippers-Hollmann s.l-h@gmx.de wrote:
> > 
> > > Hi
> > > 
> > > On 2018-05-04, Ram Chandra Jangir wrote:
> > > 
> > > > -   Rebased the patches for 4.14
> > > >     
> > > > -   Dropped spi-qup and 0027, 0028, 0029
> > > >     
> > > >     clk patches since it's already included
> > > >     
> > > >     in upstream.
> > > >     
> > > > 
> > > > Tested on IPQ AP148 Board:
> > > > 
> > > > 1.  NOR boot and NAND boot
> > > > 2.  Tested USB and PCIe interfaces
> > > > 3.  WDOG test
> > > > 4.  cpu frequency scaling
> > > > 5.  ethernet, 2G and 5G WiFi
> > > > 6.  ubi sysupgrade
> > > > 
> > > > Signed-off-by: Ram Chandra Jangir rjangir@codeaurora.org
> > > > --------------------------------------------------------
> > > > 
> > > > Changes since v1:
> > > > 
> > > > Fixes PCIe ext reset for IPQ8065 boards
> > > > 
> > > > With these changes my ZyXEL nbg6817 (ipq8065) works fine (PCIe and
> > > 
> > > wlan), thanks a lot!
> > > 
> > > New, working, gzip compressed dmesg, attached.
> > > 
> > > Regards
> > > 
> > > Stefan Lippers-Hollmann
> > > 
> > > Lede-dev mailing list
> > > 
> > > Lede-dev@lists.infradead.org
> > > 
> > > http://lists.infradead.org/mailman/listinfo/lede-dev
> > 
> > Lede-dev mailing list
> > 
> > Lede-dev@lists.infradead.org
> > 
> > http://lists.infradead.org/mailman/listinfo/lede-dev
diff mbox series

Patch

diff --git a/target/linux/ipq806x/config-4.14 b/target/linux/ipq806x/config-4.14
new file mode 100644
index 0000000..8970f19
--- /dev/null
+++ b/target/linux/ipq806x/config-4.14
@@ -0,0 +1,502 @@ 
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_AMBA_PL08X is not set
+CONFIG_APQ_GCC_8084=y
+CONFIG_APQ_MMCC_8084=y
+CONFIG_AR8216_PHY=y
+CONFIG_ARCH_CLOCKSOURCE_DATA=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+# CONFIG_ARCH_MDM9615 is not set
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MSM8960=y
+CONFIG_ARCH_MSM8974=y
+CONFIG_ARCH_MSM8X60=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+CONFIG_ARCH_MULTI_V6_V7=y
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_QCOM=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set
+# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER is not set
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE=y
+CONFIG_ARM_CPUIDLE=y
+CONFIG_ARM_CPU_SUSPEND=y
+# CONFIG_ARM_CPU_TOPOLOGY is not set
+CONFIG_ARM_GIC=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+# CONFIG_ARM_LPAE is not set
+CONFIG_ARM_PATCH_IDIV=y
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_ARM_QCOM_CPUFREQ=y
+CONFIG_ARM_QCOM_CPUIDLE=y
+# CONFIG_ARM_SMMU is not set
+# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_UNWIND=y
+CONFIG_ARM_VIRT_EXT=y
+# CONFIG_BINFMT_FLAT is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_MQ_PCI=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_BOUNCE=y
+CONFIG_BUS_TOPOLOGY_ADHOC=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLKSRC_PROBE=y
+CONFIG_CLKSRC_QCOM=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_COMMON_CLK=y
+CONFIG_COMMON_CLK_QCOM=y
+CONFIG_CPUFREQ_DT=y
+CONFIG_CPUFREQ_DT_PLATDEV=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_GOV_ATTR_SET=y
+CONFIG_CPU_FREQ_GOV_COMMON=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_PM=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_THERMAL=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+# CONFIG_CRC32_SARWATE is not set
+CONFIG_CRC32_SLICEBY8=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_DEV_QCE=y
+CONFIG_CRYPTO_DRBG=y
+CONFIG_CRYPTO_DRBG_HMAC=y
+CONFIG_CRYPTO_DRBG_MENU=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_GF128MUL=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_JITTERENTROPY=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_NULL=y
+CONFIG_CRYPTO_NULL2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_RNG_DEFAULT=y
+CONFIG_CRYPTO_SEQIV=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_XTS=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_INCLUDE="debug/msm.S"
+CONFIG_DEBUG_QCOM_UARTDM=y
+# CONFIG_DEBUG_UART_8250 is not set
+CONFIG_DEBUG_UART_PHYS=0x16340000
+CONFIG_DEBUG_UART_VIRT=0xf6340000
+CONFIG_DEBUG_UNCOMPRESS=y
+# CONFIG_DEBUG_USER is not set
+CONFIG_DMADEVICES=y
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_OF=y
+CONFIG_DMA_VIRTUAL_CHANNELS=y
+CONFIG_DTC=y
+CONFIG_DT_IDLE_STATES=y
+# CONFIG_DWMAC_DWC_QOS_ETH is not set
+# CONFIG_DWMAC_GENERIC is not set
+CONFIG_DWMAC_IPQ806X=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_ETHERNET_PACKET_MANGLE=y
+CONFIG_FIXED_PHY=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ARM_ARCH_TIMER=y
+CONFIG_HAVE_ARM_SMCCC=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_CBPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+CONFIG_HWMON=y
+CONFIG_HWSPINLOCK=y
+CONFIG_HWSPINLOCK_QCOM=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
+CONFIG_HZ_FIXED=0
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_QUP=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IOMMU_HELPER=y
+# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
+# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
+CONFIG_IOMMU_SUPPORT=y
+# CONFIG_IPQ_GCC_4019 is not set
+CONFIG_IPQ_GCC_806X=y
+# CONFIG_IPQ_GCC_8074 is not set
+# CONFIG_IPQ_LCC_806X is not set
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_KPSS_XCC=y
+CONFIG_KRAITCC=y
+CONFIG_KRAIT_CLOCKS=y
+CONFIG_KRAIT_L2_ACCESSORS=y
+CONFIG_LIBFDT=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MDIO_GPIO=y
+# CONFIG_MDM_GCC_9615 is not set
+# CONFIG_MDM_LCC_9615 is not set
+# CONFIG_MFD_MAX77620 is not set
+CONFIG_MFD_QCOM_RPM=y
+# CONFIG_MFD_SPMI_PMIC is not set
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_MMC=y
+CONFIG_MMC_ARMMMCI=y
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=16
+CONFIG_MMC_QCOM_DML=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_MSM=y
+# CONFIG_MMC_SDHCI_PCI is not set
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_TIFM_SD is not set
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_GCC_8660=y
+# CONFIG_MSM_GCC_8916 is not set
+CONFIG_MSM_GCC_8960=y
+CONFIG_MSM_GCC_8974=y
+# CONFIG_MSM_GCC_8994 is not set
+# CONFIG_MSM_GCC_8996 is not set
+# CONFIG_MSM_IOMMU is not set
+# CONFIG_MSM_LCC_8960 is not set
+CONFIG_MSM_MMCC_8960=y
+CONFIG_MSM_MMCC_8974=y
+# CONFIG_MSM_MMCC_8996 is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_NAND_QCOM=y
+# CONFIG_MTD_PHYSMAP_OF_VERSATILE is not set
+CONFIG_MTD_QCOM_SMEM_PARTS=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPLIT_FIRMWARE=y
+CONFIG_MTD_SPLIT_FIT_FW=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+# CONFIG_MTD_UBI_FASTMAP is not set
+# CONFIG_MTD_UBI_GLUEBI is not set
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NEON=y
+CONFIG_NET_DSA=y
+CONFIG_NET_DSA_HWMON=y
+CONFIG_NET_DSA_QCA8K=y
+CONFIG_NET_DSA_TAG_QCA=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_PTP_CLASSIFY=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_NLS=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_NVMEM=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_ADDRESS_PCI=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_NET=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PADATA=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PCI=y
+CONFIG_PCIEAER=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIE_DW=y
+CONFIG_PCIE_QCOM=y
+CONFIG_PCI_DEBUG=y
+CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_MSI_IRQ_DOMAIN=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+# CONFIG_PHY_QCOM_APQ8064_SATA is not set
+CONFIG_PHY_QCOM_IPQ806X_SATA=y
+# CONFIG_PHY_QCOM_QMP is not set
+# CONFIG_PHY_QCOM_QUSB2 is not set
+# CONFIG_PHY_QCOM_UFS is not set
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_APQ8064=y
+# CONFIG_PINCTRL_APQ8084 is not set
+# CONFIG_PINCTRL_IPQ4019 is not set
+CONFIG_PINCTRL_IPQ8064=y
+# CONFIG_PINCTRL_IPQ8074 is not set
+# CONFIG_PINCTRL_MDM9615 is not set
+CONFIG_PINCTRL_MSM=y
+# CONFIG_PINCTRL_MSM8660 is not set
+# CONFIG_PINCTRL_MSM8916 is not set
+# CONFIG_PINCTRL_MSM8960 is not set
+# CONFIG_PINCTRL_MSM8994 is not set
+# CONFIG_PINCTRL_MSM8996 is not set
+CONFIG_PINCTRL_MSM8X74=y
+# CONFIG_PINCTRL_QCOM_SPMI_PMIC is not set
+# CONFIG_PINCTRL_QCOM_SSBI_PMIC is not set
+# CONFIG_PL330_DMA is not set
+CONFIG_PM_OPP=y
+CONFIG_POWER_RESET=y
+# CONFIG_POWER_RESET_BRCMKONA is not set
+CONFIG_POWER_RESET_MSM=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_QCOM_ADM=y
+CONFIG_QCOM_BAM_DMA=y
+CONFIG_QCOM_CLK_RPM=y
+# CONFIG_QCOM_EBI2 is not set
+CONFIG_QCOM_GDSC=y
+CONFIG_QCOM_GSBI=y
+CONFIG_QCOM_HFPLL=y
+# CONFIG_QCOM_IOMMU is not set
+CONFIG_QCOM_PM=y
+# CONFIG_QCOM_Q6V5_PIL is not set
+CONFIG_QCOM_QFPROM=y
+CONFIG_QCOM_RPMCC=y
+CONFIG_QCOM_SCM=y
+CONFIG_QCOM_SCM_32=y
+# CONFIG_QCOM_SMD is not set
+CONFIG_QCOM_SMEM=y
+# CONFIG_QCOM_SMP2P is not set
+# CONFIG_QCOM_SMSM is not set
+CONFIG_QCOM_TCSR=y
+CONFIG_QCOM_TSENS=y
+# CONFIG_QCOM_WCNSS_PIL is not set
+CONFIG_QCOM_WDT=y
+# CONFIG_QRTR is not set
+CONFIG_RAS=y
+CONFIG_RATIONAL=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGMAP_SPI=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_QCOM_RPM=y
+# CONFIG_REGULATOR_QCOM_SPMI is not set
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RFS_ACCEL=y
+# CONFIG_RPMSG_QCOM_SMD is not set
+CONFIG_RPS=y
+CONFIG_RTC_CLASS=y
+# CONFIG_RTC_DRV_CMOS is not set
+CONFIG_RTC_I2C_AND_SPI=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_SCHED_INFO is not set
+# CONFIG_SCSI_DMA is not set
+CONFIG_SERIAL_8250_FSL=y
+# CONFIG_SERIAL_AMBA_PL011 is not set
+CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+# CONFIG_SPI_CADENCE_QUADSPI is not set
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_QUP=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB=y
+CONFIG_SRCU=y
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_PLATFORM=y
+CONFIG_SWCONFIG=y
+CONFIG_SWCONFIG_LEDS=y
+CONFIG_SWIOTLB=y
+CONFIG_SWPHY=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_HWMON=y
+CONFIG_THERMAL_OF=y
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TREE_RCU=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_USB=y
+CONFIG_USB_COMMON=y
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_QCOM_8X16_PHY is not set
+CONFIG_USB_SUPPORT=y
+# CONFIG_USB_UHCI_HCD is not set
+CONFIG_USE_OF=y
+CONFIG_VDSO=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-ap148.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
new file mode 100644
index 0000000..a3df829
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
@@ -0,0 +1,250 @@ 
+#include "qcom-ipq8064-v1.0.dtsi"
+
+/ {
+	model = "Qualcomm IPQ8064/AP148";
+	compatible = "qcom,ipq8064-ap148", "qcom,ipq8064";
+
+	memory@0 {
+		reg = <0x42000000 0x1e000000>;
+		device_type = "memory";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+	};
+
+	aliases {
+		serial0 = &gsbi4_serial;
+		mdio-gpio0 = &mdio0;
+	};
+
+	chosen {
+		linux,stdout-path = "serial0:115200n8";
+	};
+
+	soc {
+		pinmux@800000 {
+			i2c4_pins: i2c4_pinmux {
+				pins = "gpio12", "gpio13";
+				function = "gsbi4";
+				bias-disable;
+			};
+
+			spi_pins: spi_pins {
+				mux {
+					pins = "gpio18", "gpio19", "gpio21";
+					function = "gsbi5";
+					drive-strength = <10>;
+					bias-none;
+				};
+			};
+			nand_pins: nand_pins {
+				mux {
+					pins = "gpio34", "gpio35", "gpio36",
+					       "gpio37", "gpio38", "gpio39",
+					       "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					function = "nand";
+					drive-strength = <10>;
+					bias-disable;
+				};
+				pullups {
+					pins = "gpio39";
+					bias-pull-up;
+				};
+				hold {
+					pins = "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					bias-bus-hold;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			rgmii2_pins: rgmii2_pins {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+					       "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
+					function = "rgmii2";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+		};
+
+		gsbi@16300000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			serial@16340000 {
+				status = "ok";
+			};
+
+			/*
+			* The i2c device on gsbi4 should not be enabled.
+			* On ipq806x designs gsbi4 i2c is meant for exclusive
+			* RPM usage. Turning this on in kernel manifests as
+			* i2c failure for the RPM.
+			*/
+		};
+
+		gsbi5: gsbi@1a200000 {
+			qcom,mode = <GSBI_PROT_SPI>;
+			status = "ok";
+
+			spi4: spi@1a280000 {
+				status = "ok";
+				spi-max-frequency = <50000000>;
+
+				pinctrl-0 = <&spi_pins>;
+				pinctrl-names = "default";
+
+				cs-gpios = <&qcom_pinmux 20 0>;
+
+				flash: m25p80@0 {
+					compatible = "s25fl256s1";
+					#address-cells = <1>;
+					#size-cells = <1>;
+					spi-max-frequency = <50000000>;
+					reg = <0>;
+
+					partitions {
+						compatible = "qcom,smem";
+					};
+				};
+			};
+		};
+
+		sata-phy@1b400000 {
+			status = "ok";
+		};
+
+		sata@29000000 {
+			status = "ok";
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			status = "ok";
+		};
+
+		usb30@0 {
+			status = "ok";
+		};
+
+		usb30@1 {
+			status = "ok";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+			force_gen1 = <1>;
+		};
+
+		nand@1ac00000 {
+			status = "ok";
+
+			pinctrl-0 = <&nand_pins>;
+			pinctrl-names = "default";
+
+			cs0 {
+				reg = <0>;
+				compatible = "qcom,nandcs";
+
+				nand-ecc-strength = <4>;
+				nand-bus-width = <8>;
+				nand-ecc-step-size = <512>;
+
+				partitions {
+					compatible = "qcom,smem";
+				};
+			};
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>;
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0x6a545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+					>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+			};
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			qcom,id = <1>;
+
+			pinctrl-0 = <&rgmii2_pins>;
+			pinctrl-names = "default";
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+	};
+};
+
+&adm_dma {
+	status = "ok";
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-c2600.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-c2600.dts
new file mode 100644
index 0000000..a4fd134
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-c2600.dts
@@ -0,0 +1,500 @@ 
+#include "qcom-ipq8064-v1.0.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "TP-Link Archer C2600";
+	compatible = "tplink,c2600", "qcom,ipq8064";
+
+	memory@0 {
+		reg = <0x42000000 0x1e000000>;
+		device_type = "memory";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+	};
+
+	aliases {
+		serial0 = &gsbi4_serial;
+		mdio-gpio0 = &mdio0;
+
+		led-boot = &power;
+		led-failsafe = &general;
+		led-running = &power;
+		led-upgrade = &general;
+	};
+
+	chosen {
+		linux,stdout-path = "serial0:115200n8";
+	};
+
+	soc {
+		pinmux@800000 {
+			button_pins: button_pins {
+				mux {
+					pins = "gpio16", "gpio54", "gpio65";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			i2c4_pins: i2c4_pinmux {
+				mux {
+					pins = "gpio12", "gpio13";
+					function = "gsbi4";
+					drive-strength = <12>;
+					bias-disable;
+				};
+			};
+
+			led_pins: led_pins {
+				mux {
+					pins = "gpio6", "gpio7", "gpio8", "gpio9", "gpio26", "gpio33",
+					       "gpio53", "gpio66";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			spi_pins: spi_pins {
+				mux {
+					pins = "gpio18", "gpio19", "gpio21";
+					function = "gsbi5";
+					bias-pull-down;
+				};
+
+				data {
+					pins = "gpio18", "gpio19";
+					drive-strength = <10>;
+				};
+
+				cs {
+					pins = "gpio20";
+					function = "gpio";
+					drive-strength = <10>;
+					bias-pull-up;
+				};
+
+				clk {
+					pins = "gpio21";
+					drive-strength = <12>;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			rgmii2_pins: rgmii2_pins {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+					       "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
+					function = "rgmii2";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			usb0_pwr_en_pin: usb0_pwr_en_pin {
+				mux {
+					pins = "gpio25";
+					function = "gpio";
+					drive-strength = <10>;
+					bias-pull-up;
+					output-high;
+				};
+			};
+
+			usb1_pwr_en_pin: usb1_pwr_en_pin {
+				mux {
+					pins = "gpio23";
+					function = "gpio";
+					drive-strength = <10>;
+					bias-pull-up;
+					output-high;
+				};
+			};
+		};
+
+		gsbi@16300000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			serial@16340000 {
+				status = "ok";
+			};
+			/*
+			 * The i2c device on gsbi4 should not be enabled.
+			 * On ipq806x designs gsbi4 i2c is meant for exclusive
+			 * RPM usage. Turning this on in kernel manifests as
+			 * i2c failure for the RPM.
+			 */
+		};
+
+		gsbi5: gsbi@1a200000 {
+			qcom,mode = <GSBI_PROT_SPI>;
+			status = "ok";
+
+			spi5: spi@1a280000 {
+				status = "ok";
+
+				pinctrl-0 = <&spi_pins>;
+				pinctrl-names = "default";
+
+				cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>;
+
+				flash: m25p80@0 {
+					compatible = "jedec,spi-nor";
+					#address-cells = <1>;
+					#size-cells = <1>;
+					spi-max-frequency = <50000000>;
+					reg = <0>;
+
+					SBL1@0 {
+						label = "SBL1";
+						reg = <0x0 0x20000>;
+						read-only;
+					};
+
+					MIBIB@20000 {
+						label = "MIBIB";
+						reg = <0x20000 0x20000>;
+						read-only;
+					};
+
+					SBL2@40000 {
+						label = "SBL2";
+						reg = <0x40000 0x20000>;
+						read-only;
+					};
+
+					SBL3@60000 {
+						label = "SBL3";
+						reg = <0x60000 0x30000>;
+						read-only;
+					};
+
+					DDRCONFIG@90000 {
+						label = "DDRCONFIG";
+						reg = <0x90000 0x10000>;
+						read-only;
+					};
+
+					SSD@a0000 {
+						label = "SSD";
+						reg = <0xa0000 0x10000>;
+						read-only;
+					};
+
+					TZ@b0000 {
+						label = "TZ";
+						reg = <0xb0000 0x30000>;
+						read-only;
+					};
+
+					RPM@e0000 {
+						label = "RPM";
+						reg = <0xe0000 0x20000>;
+						read-only;
+					};
+
+					fs-uboot@100000 {
+						label = "fs-uboot";
+						reg = <0x100000 0x70000>;
+						read-only;
+					};
+
+					uboot-env@170000 {
+						label = "uboot-env";
+						reg = <0x170000 0x40000>;
+						read-only;
+					};
+
+					radio@1b0000 {
+						label = "radio";
+						reg = <0x1b0000 0x40000>;
+						read-only;
+					};
+
+					os-image@1f0000 {
+						label = "os-image";
+						reg = <0x1f0000 0x200000>;
+					};
+
+					rootfs@3f0000 {
+						label = "rootfs";
+						reg = <0x3f0000 0x1b00000>;
+					};
+
+					defaultmac: default-mac@1ef0000 {
+						label = "default-mac";
+						reg = <0x1ef0000 0x00200>;
+						read-only;
+					};
+
+					pin@1ef0200 {
+						label = "pin";
+						reg = <0x1ef0200 0x00200>;
+						read-only;
+					};
+
+					product-info@1ef0400 {
+						label = "product-info";
+						reg = <0x1ef0400 0x0fc00>;
+						read-only;
+					};
+
+					partition-table@1f00000 {
+						label = "partition-table";
+						reg = <0x1f00000 0x10000>;
+						read-only;
+					};
+
+					soft-version@1f10000 {
+						label = "soft-version";
+						reg = <0x1f10000 0x10000>;
+						read-only;
+					};
+
+					support-list@1f20000 {
+						label = "support-list";
+						reg = <0x1f20000 0x10000>;
+						read-only;
+					};
+
+					profile@1f30000 {
+						label = "profile";
+						reg = <0x1f30000 0x10000>;
+						read-only;
+					};
+
+					default-config@1f40000 {
+						label = "default-config";
+						reg = <0x1f40000 0x10000>;
+						read-only;
+					};
+
+					user-config@1f50000 {
+						label = "user-config";
+						reg = <0x1f50000 0x40000>;
+						read-only;
+					};
+
+					qos-db@1f90000 {
+						label = "qos-db";
+						reg = <0x1f90000 0x40000>;
+						read-only;
+					};
+
+					usb-config@1fd0000 {
+						label = "usb-config";
+						reg = <0x1fd0000 0x10000>;
+						read-only;
+					};
+
+					log@1fe0000 {
+						label = "log";
+						reg = <0x1fe0000 0x20000>;
+						read-only;
+					};
+				};
+			};
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			status = "ok";
+		};
+
+		usb30@0 {
+			status = "ok";
+
+			pinctrl-0 = <&usb0_pwr_en_pin>;
+			pinctrl-names = "default";
+		};
+
+		usb30@1 {
+			status = "ok";
+
+			pinctrl-0 = <&usb1_pwr_en_pin>;
+			pinctrl-names = "default";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+			force_gen1 = <1>;
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0x6a545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+					>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+			};
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			qcom,id = <1>;
+
+			pinctrl-0 = <&rgmii2_pins>;
+			pinctrl-names = "default";
+
+			mtd-mac-address = <&defaultmac 0x8>;
+			mtd-mac-address-increment = <1>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+
+			mtd-mac-address = <&defaultmac 0x8>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		rpm@108000 {
+			pinctrl-0 = <&i2c4_pins>;
+			pinctrl-names = "default";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		wifi {
+			label = "wifi";
+			gpios = <&qcom_pinmux 49 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RFKILL>;
+		};
+
+		reset {
+			label = "reset";
+			gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+
+		wps {
+			label = "wps";
+			gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+		};
+
+		ledswitch {
+			label = "ledswitch";
+			gpios = <&qcom_pinmux 16 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_LIGHTS_TOGGLE>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_pins>;
+		pinctrl-names = "default";
+
+		lan {
+			label = "c2600:white:lan";
+			gpios = <&qcom_pinmux 6 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb4 {
+			label = "c2600:white:usb_4";
+			gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb2 {
+			label = "c2600:white:usb_2";
+			gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>;
+		};
+
+		wps {
+			label = "c2600:white:wps";
+			gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
+		};
+
+		wan_amber {
+			label = "c2600:amber:wan";
+			gpios = <&qcom_pinmux 26 GPIO_ACTIVE_LOW>;
+		};
+
+		wan_white {
+			label = "c2600:white:wan";
+			gpios = <&qcom_pinmux 33 GPIO_ACTIVE_LOW>;
+		};
+
+		power: power {
+			label = "c2600:white:power";
+			gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		general: general {
+			label = "c2600:white:general";
+			gpios = <&qcom_pinmux 66 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
+
+&adm_dma {
+	status = "ok";
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-d7800.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-d7800.dts
new file mode 100644
index 0000000..b7c49cc
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-d7800.dts
@@ -0,0 +1,419 @@ 
+#include "qcom-ipq8064-v1.0.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Netgear Nighthawk X4 D7800";
+	compatible = "netgear,d7800", "qcom,ipq8064";
+
+	memory@0 {
+		reg = <0x42000000 0xe000000>;
+		device_type = "memory";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+	};
+
+	aliases {
+		serial0 = &gsbi4_serial;
+		mdio-gpio0 = &mdio0;
+
+		led-boot = &power_white;
+		led-failsafe = &power_amber;
+		led-running = &power_white;
+		led-upgrade = &power_amber;
+	};
+
+	chosen {
+		bootargs = "rootfstype=squashfs noinitrd";
+		linux,stdout-path = "serial0:115200n8";
+	};
+
+	soc {
+		pinmux@800000 {
+			button_pins: button_pins {
+				mux {
+					pins = "gpio6", "gpio54", "gpio65";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			i2c4_pins: i2c4_pinmux {
+				mux {
+					pins = "gpio12", "gpio13";
+					function = "gsbi4";
+					drive-strength = <12>;
+					bias-disable;
+				};
+			};
+
+			led_pins: led_pins {
+				mux {
+					pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23",
+						"gpio24","gpio26", "gpio53", "gpio64";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			nand_pins: nand_pins {
+				mux {
+					pins = "gpio34", "gpio35", "gpio36",
+					       "gpio37", "gpio38", "gpio39",
+					       "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					function = "nand";
+					drive-strength = <10>;
+					bias-disable;
+				};
+				pullups {
+					pins = "gpio39";
+					bias-pull-up;
+				};
+				hold {
+					pins = "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					bias-bus-hold;
+				};
+			};
+
+			rgmii2_pins: rgmii2_pins {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+					       "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
+					function = "rgmii2";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			usb0_pwr_en_pins: usb0_pwr_en_pins {
+				mux {
+					pins = "gpio15";
+					function = "gpio";
+					drive-strength = <12>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+
+			usb1_pwr_en_pins: usb1_pwr_en_pins {
+				mux {
+					pins = "gpio16", "gpio68";
+					function = "gpio";
+					drive-strength = <12>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+		};
+
+		gsbi@16300000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			serial@16340000 {
+				status = "ok";
+			};
+			/*
+			 * The i2c device on gsbi4 should not be enabled.
+			 * On ipq806x designs gsbi4 i2c is meant for exclusive
+			 * RPM usage. Turning this on in kernel manifests as
+			 * i2c failure for the RPM.
+			 */
+		};
+
+		sata-phy@1b400000 {
+			status = "ok";
+		};
+
+		sata@29000000 {
+			status = "ok";
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			status = "ok";
+		};
+
+		usb30@0 {
+			status = "ok";
+
+			pinctrl-0 = <&usb0_pwr_en_pins>;
+			pinctrl-names = "default";
+		};
+
+		usb30@1 {
+			status = "ok";
+
+			pinctrl-0 = <&usb1_pwr_en_pins>;
+			pinctrl-names = "default";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+			reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&pcie0_pins>;
+			pinctrl-names = "default";
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+			reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&pcie1_pins>;
+			pinctrl-names = "default";
+			force_gen1 = <1>;
+		};
+
+		nand@1ac00000 {
+			status = "ok";
+
+			pinctrl-0 = <&nand_pins>;
+			pinctrl-names = "default";
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			cs0 {
+				reg = <0>;
+				compatible = "qcom,nandcs";
+
+				nand-ecc-strength = <4>;
+				nand-bus-width = <8>;
+				nand-ecc-step-size = <512>;
+
+				partitions {
+					compatible = "fixed-partitions";
+					#address-cells = <1>;
+					#size-cells = <1>;
+
+					qcadata@0 {
+						label = "qcadata";
+						reg = <0x0000000 0x0c80000>;
+						read-only;
+					};
+
+					APPSBL@c80000 {
+						label = "APPSBL";
+						reg = <0x0c80000 0x0500000>;
+						read-only;
+					};
+
+					APPSBLENV@1180000 {
+						label = "APPSBLENV";
+						reg = <0x1180000 0x0080000>;
+						read-only;
+					};
+
+					art: art@1200000 {
+						label = "art";
+						reg = <0x1200000 0x0140000>;
+						read-only;
+					};
+
+					artbak: art@1340000 {
+						label = "artbak";
+						reg = <0x1340000 0x0140000>;
+						read-only;
+					};
+
+					kernel@1480000 {
+						label = "kernel";
+						reg = <0x1480000 0x0200000>;
+					};
+
+					ubi@1680000 {
+						label = "ubi";
+						reg = <0x1680000 0x1E00000>;
+					};
+
+					netgear@3480000 {
+						label = "netgear";
+						reg = <0x3480000 0x4480000>;
+						read-only;
+					};
+
+					reserve@7900000 {
+						label = "reserve";
+						reg = <0x7900000 0x0700000>;
+						read-only;
+					};
+
+					firmware@1480000 {
+						label = "firmware";
+						reg = <0x1480000 0x2000000>;
+					};
+				};
+			};
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0x6a545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+					>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+			};
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			phy-handle = <&phy4>;
+			qcom,id = <1>;
+
+			pinctrl-0 = <&rgmii2_pins>;
+			pinctrl-names = "default";
+
+			mtd-mac-address = <&art 6>;
+		};
+
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+
+			mtd-mac-address = <&art 0>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		rpm@108000 {
+			pinctrl-0 = <&i2c4_pins>;
+			pinctrl-names = "default";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		wifi {
+			label = "wifi";
+			gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RFKILL>;
+		};
+
+		reset {
+			label = "reset";
+			gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+
+		wps {
+			label = "wps";
+			gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_pins>;
+		pinctrl-names = "default";
+
+		usb1 {
+			label = "d7800:white:usb1";
+			gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb2 {
+			label = "d7800:white:usb2";
+			gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>;
+		};
+
+		power_amber: power_amber {
+			label = "d7800:amber:power";
+			gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
+		};
+
+		wan_white {
+			label = "d7800:white:wan";
+			gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>;
+		};
+
+		wan_amber {
+			label = "d7800:amber:wan";
+			gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>;
+		};
+
+		wps {
+			label = "d7800:white:wps";
+			gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>;
+		};
+
+		esata {
+			label = "d7800:white:esata";
+			gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>;
+		};
+
+		power_white: power_white {
+			label = "d7800:white:power";
+			gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		wifi {
+			label = "d7800:white:wifi";
+			gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
+
+&adm_dma {
+	status = "ok";
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-db149.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-db149.dts
new file mode 100644
index 0000000..4c56866
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-db149.dts
@@ -0,0 +1,236 @@ 
+#include "qcom-ipq8064-v1.0.dtsi"
+
+/ {
+	model = "Qualcomm IPQ8064/DB149";
+	compatible = "qcom,ipq8064-db149", "qcom,ipq8064";
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+	};
+
+	alias {
+		serial0 = &uart2;
+		mdio-gpio0 = &mdio0;
+	};
+
+	chosen {
+		linux,stdout-path = "serial0:115200n8";
+	};
+
+	soc {
+		pinmux@800000 {
+			i2c4_pins: i2c4_pinmux {
+				pins = "gpio12", "gpio13";
+				function = "gsbi4";
+				bias-disable;
+			};
+
+			spi_pins: spi_pins {
+				mux {
+					pins = "gpio18", "gpio19", "gpio21";
+					function = "gsbi5";
+					drive-strength = <10>;
+					bias-none;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			rgmii0_pins: rgmii0_pins {
+				mux {
+					pins = "gpio2", "gpio66";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+		};
+
+		gsbi2: gsbi@12480000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			uart2: serial@12490000 {
+				status = "ok";
+			};
+		};
+
+		gsbi5: gsbi@1a200000 {
+			qcom,mode = <GSBI_PROT_SPI>;
+			status = "ok";
+
+			spi4: spi@1a280000 {
+				status = "ok";
+				spi-max-frequency = <50000000>;
+
+				pinctrl-0 = <&spi_pins>;
+				pinctrl-names = "default";
+
+				cs-gpios = <&qcom_pinmux 20 0>;
+
+				flash: m25p80@0 {
+					compatible = "s25fl256s1";
+					#address-cells = <1>;
+					#size-cells = <1>;
+					spi-max-frequency = <50000000>;
+					reg = <0>;
+					m25p,fast-read;
+
+					partition@0 {
+						label = "lowlevel_init";
+						reg = <0x0 0x1b0000>;
+					};
+
+					partition@1 {
+						label = "u-boot";
+						reg = <0x1b0000 0x80000>;
+					};
+
+					partition@2 {
+						label = "u-boot-env";
+						reg = <0x230000 0x40000>;
+					};
+
+					partition@3 {
+						label = "caldata";
+						reg = <0x270000 0x40000>;
+					};
+
+					partition@4 {
+						label = "firmware";
+						reg = <0x2b0000 0x1d50000>;
+					};
+				};
+			};
+		};
+
+		sata-phy@1b400000 {
+			status = "ok";
+		};
+
+		sata@29000000 {
+			status = "ok";
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			status = "ok";
+		};
+
+		usb30@0 {
+			status = "ok";
+		};
+
+		usb30@1 {
+			status = "ok";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+		};
+
+		pcie2: pci@1b900000 {
+			status = "ok";
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>;
+
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0x6a545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+				>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+			};
+
+			phy6: ethernet-phy@6 {
+				device_type = "ethernet-phy";
+				reg = <6>;
+			};
+
+			phy7: ethernet-phy@7 {
+				device_type = "ethernet-phy";
+				reg = <7>;
+			};
+		};
+
+		gmac0: ethernet@37000000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			qcom,id = <0>;
+			phy-handle = <&phy4>;
+
+			pinctrl-0 = <&rgmii0_pins>;
+			pinctrl-names = "default";
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <1>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+			phy-handle = <&phy6>;
+		};
+
+		gmac3: ethernet@37600000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <3>;
+			phy-handle = <&phy7>;
+		};
+	};
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts
new file mode 100644
index 0000000..a9c5248
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-ea8500.dts
@@ -0,0 +1,406 @@ 
+#include "qcom-ipq8064-v1.0.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Linksys EA8500 WiFi Router";
+	compatible = "linksys,ea8500", "qcom,ipq8064";
+
+	memory@0 {
+		reg = <0x42000000 0x1e000000>;
+		device_type = "memory";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+	};
+
+	aliases {
+		serial0 = &gsbi4_serial;
+		mdio-gpio0 = &mdio0;
+
+		led-boot = &power;
+		led-failsafe = &power;
+		led-running = &power;
+		led-upgrade = &power;
+	};
+
+	chosen {
+		bootargs = "console=ttyMSM0,115200n8";
+		linux,stdout-path = "serial0:115200n8";
+		append-rootblock = "ubi.mtd=";  /* append to bootargs adding the root deviceblock nbr from bootloader */
+	};
+
+	soc {
+		pinmux@800000 {
+			button_pins: button_pins {
+				mux {
+					pins = "gpio65", "gpio67", "gpio68";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			i2c4_pins: i2c4_pinmux {
+				mux {
+					pins = "gpio12", "gpio13";
+					function = "gsbi4";
+					drive-strength = <12>;
+					bias-disable;
+				};
+			};
+
+			led_pins: led_pins {
+				mux {
+					pins = "gpio6", "gpio53", "gpio54";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			nand_pins: nand_pins {
+				mux {
+					pins = "gpio34", "gpio35", "gpio36",
+					       "gpio37", "gpio38", "gpio39",
+					       "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					function = "nand";
+					drive-strength = <10>;
+					bias-disable;
+				};
+				pullups {
+					pins = "gpio39";
+					bias-pull-up;
+				};
+				hold {
+					pins = "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					bias-bus-hold;
+				};
+			};
+
+			rgmii2_pins: rgmii2_pins {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+					       "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
+					function = "rgmii2";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+		};
+
+		gsbi@16300000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			serial@16340000 {
+				status = "ok";
+			};
+			/*
+			 * The i2c device on gsbi4 should not be enabled.
+			 * On ipq806x designs gsbi4 i2c is meant for exclusive
+			 * RPM usage. Turning this on in kernel manifests as
+			 * i2c failure for the RPM.
+			 */
+		};
+
+		sata-phy@1b400000 {
+			status = "ok";
+		};
+
+		sata@29000000 {
+			status = "ok";
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			status = "ok";
+		};
+
+		usb30@0 {
+			status = "ok";
+		};
+
+		usb30@1 {
+			status = "ok";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+			force_gen1 = <1>;
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+		};
+
+		pcie2: pci@1b900000 {
+			status = "ok";
+		};
+
+		nand@1ac00000 {
+			status = "ok";
+
+			pinctrl-0 = <&nand_pins>;
+			pinctrl-names = "default";
+
+			cs0 {
+				reg = <0>;
+				compatible = "qcom,nandcs";
+
+				nand-ecc-strength = <4>;
+				nand-bus-width = <8>;
+				nand-ecc-step-size = <512>;
+
+				partitions {
+					compatible = "fixed-partitions";
+					#address-cells = <1>;
+					#size-cells = <1>;
+
+					SBL1@0 {
+						label = "SBL1";
+						reg = <0x0000000 0x0040000>;
+						read-only;
+					};
+
+					MIBIB@40000 {
+						label = "MIBIB";
+						reg = <0x0040000 0x0140000>;
+						read-only;
+					};
+
+					SBL2@180000 {
+						label = "SBL2";
+						reg = <0x0180000 0x0140000>;
+						read-only;
+					};
+
+					SBL3@2c0000 {
+						label = "SBL3";
+						reg = <0x02c0000 0x0280000>;
+						read-only;
+					};
+
+					DDRCONFIG@540000 {
+						label = "DDRCONFIG";
+						reg = <0x0540000 0x0120000>;
+						read-only;
+					};
+
+					SSD@660000 {
+						label = "SSD";
+						reg = <0x0660000 0x0120000>;
+						read-only;
+					};
+
+					TZ@780000 {
+						label = "TZ";
+						reg = <0x0780000 0x0280000>;
+						read-only;
+					};
+
+					RPM@a00000 {
+						label = "RPM";
+						reg = <0x0a00000 0x0280000>;
+						read-only;
+					};
+
+					art: art@c80000 {
+						label = "art";
+						reg = <0x0c80000 0x0140000>;
+						read-only;
+					};
+
+					APPSBL@dc0000 {
+						label = "APPSBL";
+						reg = <0x0dc0000 0x0100000>;
+						read-only;
+					};
+
+					u_env@ec0000 {
+						label = "u_env";
+						reg = <0x0ec0000 0x0040000>;
+					};
+
+					s_env@f00000 {
+						label = "s_env";
+						reg = <0x0f00000 0x0040000>;
+					};
+
+					devinfo@f40000 {
+						label = "devinfo";
+						reg = <0x0f40000 0x0040000>;
+					};
+
+					linux@f80000 {
+						label = "kernel1";
+						reg = <0x0f80000 0x2800000>;  /* 3 MB spill to rootfs*/
+					};
+
+					rootfs@1280000 {
+						label = "rootfs1";
+						reg = <0x1280000 0x2500000>;
+					};
+
+					linux2@3780000 {
+						label = "kernel2";
+						reg = <0x3780000 0x2800000>;
+					};
+
+					rootfs2@3a80000 {
+						label = "rootfs2";
+						reg = <0x3a80000 0x2500000>;
+					};
+
+					syscfg@5f80000 {
+						label = "syscfg";
+						reg = <0x5f80000 0x2080000>;
+					};
+				};
+			};
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0x6a545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+					>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+			};
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			qcom,id = <1>;
+			qcom,phy_mdio_addr = <4>;
+			qcom,poll_required = <1>;
+			qcom,rgmii_delay = <0>;
+			qcom,emulation = <0>;
+			pinctrl-0 = <&rgmii2_pins>;
+			pinctrl-names = "default";
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+		//lan
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+			qcom,phy_mdio_addr = <0>;	/* none */
+			qcom,poll_required = <0>;	/* no polling */
+			qcom,rgmii_delay = <0>;
+			qcom,emulation = <0>;
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		rpm@108000 {
+			pinctrl-0 = <&i2c4_pins>;
+			pinctrl-names = "default";
+		};
+
+		adm_dma: dma@18300000 {
+			status = "ok";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		wifi {
+			label = "wifi";
+			gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RFKILL>;
+		};
+
+		reset {
+			label = "reset";
+			gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART >;
+		};
+
+		wps {
+			label = "wps";
+			gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_pins>;
+		pinctrl-names = "default";
+
+		wps {
+			label = "ea8500:green:wps";
+			gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
+		};
+
+		power: power {
+			label = "ea8500:white:power";
+			gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>;
+			default-state = "keep";
+		};
+
+		wifi {
+			label = "ea8500:green:wifi";
+			gpios = <&qcom_pinmux 54 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-r7500.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-r7500.dts
new file mode 100644
index 0000000..3445a79
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-r7500.dts
@@ -0,0 +1,394 @@ 
+#include "qcom-ipq8064-v1.0.dtsi"
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/soc/qcom,tcsr.h>
+
+/ {
+	model = "Netgear Nighthawk X4 R7500";
+	compatible = "netgear,r7500", "qcom,ipq8064";
+
+	memory@0 {
+		reg = <0x42000000 0xe000000>;
+		device_type = "memory";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+	};
+
+	aliases {
+		serial0 = &gsbi4_serial;
+		mdio-gpio0 = &mdio0;
+
+		led-boot = &power_white;
+		led-failsafe = &power_amber;
+		led-running = &power_white;
+		led-upgrade = &power_amber;
+	};
+
+	chosen {
+		bootargs = "rootfstype=squashfs noinitrd";
+		linux,stdout-path = "serial0:115200n8";
+	};
+
+	soc {
+		pinmux@800000 {
+			button_pins: button_pins {
+				mux {
+					pins = "gpio6", "gpio54", "gpio65";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			i2c4_pins: i2c4_pinmux {
+				mux {
+					pins = "gpio12", "gpio13";
+					function = "gsbi4";
+					drive-strength = <12>;
+					bias-disable;
+				};
+			};
+
+			led_pins: led_pins {
+				mux {
+					pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23",
+						"gpio24","gpio26", "gpio53", "gpio64";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			nand_pins: nand_pins {
+				mux {
+					pins = "gpio34", "gpio35", "gpio36",
+					       "gpio37", "gpio38", "gpio39",
+					       "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					function = "nand";
+					drive-strength = <10>;
+					bias-disable;
+				};
+				pullups {
+					pins = "gpio39";
+					bias-pull-up;
+				};
+				hold {
+					pins = "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					bias-bus-hold;
+				};
+			};
+
+			rgmii2_pins: rgmii2_pins {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+					       "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
+					function = "rgmii2";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+		};
+
+		gsbi@16300000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			serial@16340000 {
+				status = "ok";
+			};
+			/*
+			 * The i2c device on gsbi4 should not be enabled.
+			 * On ipq806x designs gsbi4 i2c is meant for exclusive
+			 * RPM usage. Turning this on in kernel manifests as
+			 * i2c failure for the RPM.
+			 */
+		};
+
+		sata-phy@1b400000 {
+			status = "ok";
+		};
+
+		sata@29000000 {
+			status = "ok";
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			clocks = <&gcc USB30_0_UTMI_CLK>;
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			clocks = <&gcc USB30_0_MASTER_CLK>;
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			clocks = <&gcc USB30_1_UTMI_CLK>;
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			clocks = <&gcc USB30_1_MASTER_CLK>;
+			status = "ok";
+		};
+
+		usb30@0 {
+			clocks = <&gcc USB30_1_MASTER_CLK>;
+			status = "ok";
+		};
+
+		usb30@1 {
+			clocks = <&gcc USB30_0_MASTER_CLK>;
+			status = "ok";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+			force_gen1 = <1>;
+		};
+
+		nand@1ac00000 {
+			status = "ok";
+
+			pinctrl-0 = <&nand_pins>;
+			pinctrl-names = "default";
+
+			cs0 {
+				reg = <0>;
+				compatible = "qcom,nandcs";
+
+				nand-ecc-strength = <4>;
+				nand-bus-width = <8>;
+				nand-ecc-step-size = <512>;
+
+				partitions {
+					compatible = "fixed-partitions";
+					#address-cells = <1>;
+					#size-cells = <1>;
+
+					qcadata@0 {
+						label = "qcadata";
+						reg = <0x0000000 0x0c80000>;
+						read-only;
+					};
+
+					APPSBL@c80000 {
+						label = "APPSBL";
+						reg = <0x0c80000 0x0500000>;
+						read-only;
+					};
+
+					APPSBLENV@1180000 {
+						label = "APPSBLENV";
+						reg = <0x1180000 0x0080000>;
+						read-only;
+					};
+
+					art: art@1200000 {
+						label = "art";
+						reg = <0x1200000 0x0140000>;
+						read-only;
+					};
+
+					kernel@1340000 {
+						label = "kernel";
+						reg = <0x1340000 0x0200000>;
+					};
+
+					ubi@1540000 {
+						label = "ubi";
+						reg = <0x1540000 0x1800000>;
+					};
+
+					netgear@2d40000 {
+						label = "netgear";
+						reg = <0x2d40000 0x0c00000>;
+						read-only;
+					};
+
+					reserve@3940000 {
+						label = "reserve";
+						reg = <0x3940000 0x46c0000>;
+						read-only;
+					};
+
+					firmware@1340000 {
+						label = "firmware";
+						reg = <0x1340000 0x1a00000>;
+					};
+				};
+			};
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0x6a545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+					>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+			};
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			qcom,id = <1>;
+
+			pinctrl-0 = <&rgmii2_pins>;
+			pinctrl-names = "default";
+
+			mtd-mac-address = <&art 6>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+
+			mtd-mac-address = <&art 0>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		rpm@108000 {
+			pinctrl-0 = <&i2c4_pins>;
+			pinctrl-names = "default";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		wifi {
+			label = "wifi";
+			gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RFKILL>;
+		};
+
+		reset {
+			label = "reset";
+			gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+
+		wps {
+			label = "wps";
+			gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_pins>;
+		pinctrl-names = "default";
+
+		usb1 {
+			label = "r7500:white:usb1";
+			gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb2 {
+			label = "r7500:white:usb2";
+			gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>;
+		};
+
+		power_amber: power_amber {
+			label = "r7500:amber:power";
+			gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
+		};
+
+		wan_white {
+			label = "r7500:white:wan";
+			gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>;
+		};
+
+		wan_amber {
+			label = "r7500:amber:wan";
+			gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>;
+		};
+
+		wps {
+			label = "r7500:white:wps";
+			gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>;
+		};
+
+		esata {
+			label = "r7500:white:esata";
+			gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>;
+		};
+
+		power_white: power_white {
+			label = "r7500:white:power";
+			gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		wifi {
+			label = "r7500:white:wifi";
+			gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
+
+&tcsr {
+	qcom,usb-ctrl-select = <TCSR_USB_SELECT_USB3_DUAL>;
+	compatible = "qcom,tcsr";
+};
+
+&adm_dma {
+	status = "ok";
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts
new file mode 100644
index 0000000..c4b0c4b
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-r7500v2.dts
@@ -0,0 +1,425 @@ 
+#include "qcom-ipq8064-v1.0.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Netgear Nighthawk X4 R7500v2";
+	compatible = "netgear,r7500v2", "qcom,ipq8064";
+
+	memory@0 {
+		reg = <0x42000000 0x1e000000>;
+		device_type = "memory";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+
+		rsvd@5fe00000 {
+			reg = <0x5fe00000 0x200000>;
+			reusable;
+		};
+	};
+
+	aliases {
+		serial0 = &gsbi4_serial;
+		mdio-gpio0 = &mdio0;
+
+		led-boot = &power;
+		led-failsafe = &power;
+		led-running = &power;
+		led-upgrade = &power;
+	};
+
+	chosen {
+		bootargs = "rootfstype=squashfs noinitrd";
+		linux,stdout-path = "serial0:115200n8";
+	};
+
+	soc {
+		pinmux@800000 {
+			button_pins: button_pins {
+				mux {
+					pins = "gpio6", "gpio54", "gpio65";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			i2c4_pins: i2c4_pinmux {
+				mux {
+					pins = "gpio12", "gpio13";
+					function = "gsbi4";
+					drive-strength = <12>;
+					bias-disable;
+				};
+			};
+
+			led_pins: led_pins {
+				mux {
+					pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23",
+						"gpio24","gpio26", "gpio53", "gpio64";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			nand_pins: nand_pins {
+				mux {
+					pins = "gpio34", "gpio35", "gpio36",
+					       "gpio37", "gpio38", "gpio39",
+					       "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					function = "nand";
+					drive-strength = <10>;
+					bias-disable;
+				};
+				pullups {
+					pins = "gpio39";
+					bias-pull-up;
+				};
+				hold {
+					pins = "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					bias-bus-hold;
+				};
+			};
+
+			rgmii2_pins: rgmii2_pins {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+					       "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
+					function = "rgmii2";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			usb0_pwr_en_pins: usb0_pwr_en_pins {
+				mux {
+					pins = "gpio15";
+					function = "gpio";
+					drive-strength = <12>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+
+			usb1_pwr_en_pins: usb1_pwr_en_pins {
+				mux {
+					pins = "gpio16", "gpio68";
+					function = "gpio";
+					drive-strength = <12>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+		};
+
+		gsbi@16300000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			serial@16340000 {
+				status = "ok";
+			};
+			/*
+			 * The i2c device on gsbi4 should not be enabled.
+			 * On ipq806x designs gsbi4 i2c is meant for exclusive
+			 * RPM usage. Turning this on in kernel manifests as
+			 * i2c failure for the RPM.
+			 */
+		};
+
+		sata-phy@1b400000 {
+			status = "ok";
+		};
+
+		sata@29000000 {
+			status = "ok";
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			status = "ok";
+		};
+
+		usb30@0 {
+			status = "ok";
+
+			pinctrl-0 = <&usb0_pwr_en_pins>;
+			pinctrl-names = "default";
+		};
+
+		usb30@1 {
+			status = "ok";
+
+			pinctrl-0 = <&usb1_pwr_en_pins>;
+			pinctrl-names = "default";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+			reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>;
+			pinctrl-0 = <&pcie0_pins>;
+			pinctrl-names = "default";
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+			reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>;
+			pinctrl-0 = <&pcie1_pins>;
+			pinctrl-names = "default";
+			force_gen1 = <1>;
+		};
+
+		nand@1ac00000 {
+			status = "ok";
+
+			pinctrl-0 = <&nand_pins>;
+			pinctrl-names = "default";
+
+			cs0 {
+				reg = <0>;
+				compatible = "qcom,nandcs";
+
+				nand-ecc-strength = <4>;
+				nand-bus-width = <8>;
+				nand-ecc-step-size = <512>;
+
+				partitions {
+					compatible = "fixed-partitions";
+					#address-cells = <1>;
+					#size-cells = <1>;
+
+					qcadata@0 {
+						label = "qcadata";
+						reg = <0x0000000 0x0c80000>;
+						read-only;
+					};
+
+					APPSBL@c80000 {
+						label = "APPSBL";
+						reg = <0x0c80000 0x0500000>;
+						read-only;
+					};
+
+					APPSBLENV@1180000 {
+						label = "APPSBLENV";
+						reg = <0x1180000 0x0080000>;
+						read-only;
+					};
+
+					art: art@1200000 {
+						label = "art";
+						reg = <0x1200000 0x0140000>;
+						read-only;
+					};
+
+					artbak: art@1340000 {
+						label = "artbak";
+						reg = <0x1340000 0x0140000>;
+						read-only;
+					};
+
+					kernel@1480000 {
+						label = "kernel";
+						reg = <0x1480000 0x0200000>;
+					};
+
+					ubi@1680000 {
+						label = "ubi";
+						reg = <0x1680000 0x1E00000>;
+					};
+
+					netgear@3480000 {
+						label = "netgear";
+						reg = <0x3480000 0x4480000>;
+						read-only;
+					};
+
+					reserve@7900000 {
+						label = "reserve";
+						reg = <0x7900000 0x0700000>;
+						read-only;
+					};
+
+					firmware@1480000 {
+						label = "firmware";
+						reg = <0x1480000 0x2000000>;
+					};
+				};
+			};
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0xaa545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+					>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+			};
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			qcom,id = <1>;
+
+			pinctrl-0 = <&rgmii2_pins>;
+			pinctrl-names = "default";
+
+			mtd-mac-address = <&art 6>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+
+			mtd-mac-address = <&art 0>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		rpm@108000 {
+			pinctrl-0 = <&i2c4_pins>;
+			pinctrl-names = "default";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		wifi {
+			label = "wifi";
+			gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RFKILL>;
+		};
+
+		reset {
+			label = "reset";
+			gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+
+		wps {
+			label = "wps";
+			gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_pins>;
+		pinctrl-names = "default";
+
+		usb1 {
+			label = "r7500v2:amber:usb1";
+			gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb3 {
+			label = "r7500v2:amber:usb3";
+			gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>;
+		};
+
+		status {
+			label = "r7500v2:amber:status";
+			gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
+		};
+
+		internet {
+			label = "r7500v2:white:internet";
+			gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>;
+		};
+
+		wan {
+			label = "r7500v2:white:wan";
+			gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>;
+		};
+
+		wps {
+			label = "r7500v2:white:wps";
+			gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>;
+		};
+
+		esata {
+			label = "r7500v2:white:esata";
+			gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>;
+		};
+
+		power: power {
+			label = "r7500v2:white:power";
+			gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		wifi {
+			label = "r7500v2:white:wifi";
+			gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
+
+&adm_dma {
+	status = "ok";
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts
new file mode 100644
index 0000000..561c49a
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-vr2600v.dts
@@ -0,0 +1,424 @@ 
+#include "qcom-ipq8064-v1.0.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "TP-Link Archer VR2600v";
+	compatible = "tplink,vr2600v", "qcom,ipq8064";
+
+	memory@0 {
+		reg = <0x42000000 0x1e000000>;
+		device_type = "memory";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+	};
+
+	aliases {
+		serial0 = &gsbi4_serial;
+		mdio-gpio0 = &mdio0;
+
+		led-boot = &power;
+		led-failsafe = &general;
+		led-running = &power;
+		led-upgrade = &general;
+	};
+
+	chosen {
+		linux,stdout-path = "serial0:115200n8";
+	};
+
+	soc {
+		pinmux@800000 {
+			led_pins: led_pins {
+				mux {
+					pins = "gpio7", "gpio8", "gpio9", "gpio16", "gpio17",
+						"gpio26", "gpio53", "gpio56", "gpio66";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			i2c4_pins: i2c4_pinmux {
+				mux {
+					pins = "gpio12", "gpio13";
+					function = "gsbi4";
+					drive-strength = <12>;
+					bias-disable;
+				};
+			};
+
+			button_pins: button_pins {
+				mux {
+					pins = "gpio54", "gpio64", "gpio65", "gpio67", "gpio68";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			spi_pins: spi_pins {
+				mux {
+					pins = "gpio18", "gpio19", "gpio21";
+					function = "gsbi5";
+					bias-pull-down;
+				};
+
+				data {
+					pins = "gpio18", "gpio19";
+					drive-strength = <10>;
+				};
+
+				cs {
+					pins = "gpio20";
+					drive-strength = <10>;
+					bias-pull-up;
+				};
+
+				clk {
+					pins = "gpio21";
+					drive-strength = <12>;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+
+			rgmii2_pins: rgmii2_pins {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+					       "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
+					function = "rgmii2";
+					drive-strength = <8>;
+					bias-disable;
+				};
+			};
+		};
+
+		gsbi@16300000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			serial@16340000 {
+				status = "ok";
+			};
+			/*
+			 * The i2c device on gsbi4 should not be enabled.
+			 * On ipq806x designs gsbi4 i2c is meant for exclusive
+			 * RPM usage. Turning this on in kernel manifests as
+			 * i2c failure for the RPM.
+			 */
+		};
+
+		gsbi5: gsbi@1a200000 {
+			qcom,mode = <GSBI_PROT_SPI>;
+			status = "ok";
+
+			spi4: spi@1a280000 {
+				status = "ok";
+
+				pinctrl-0 = <&spi_pins>;
+				pinctrl-names = "default";
+
+				cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>;
+
+				flash: W25Q128@0 {
+					compatible = "jedec,spi-nor";
+					#address-cells = <1>;
+					#size-cells = <1>;
+					spi-max-frequency = <50000000>;
+					reg = <0>;
+
+					SBL1@0 {
+						label = "SBL1";
+						reg = <0x0 0x20000>;
+						read-only;
+					};
+
+					MIBIB@20000 {
+						label = "MIBIB";
+						reg = <0x20000 0x20000>;
+						read-only;
+					};
+
+					SBL2@40000 {
+						label = "SBL2";
+						reg = <0x40000 0x40000>;
+						read-only;
+					};
+
+					SBL3@80000 {
+						label = "SBL3";
+						reg = <0x80000 0x80000>;
+						read-only;
+					};
+
+					DDRCONFIG@100000 {
+						label = "DDRCONFIG";
+						reg = <0x100000 0x10000>;
+						read-only;
+					};
+
+					SSD@110000 {
+						label = "SSD";
+						reg = <0x110000 0x10000>;
+						read-only;
+					};
+
+					TZ@120000 {
+						label = "TZ";
+						reg = <0x120000 0x80000>;
+						read-only;
+					};
+
+					RPM@1a0000 {
+						label = "RPM";
+						reg = <0x1a0000 0x80000>;
+						read-only;
+					};
+
+					APPSBL@220000 {
+						label = "APPSBL";
+						reg = <0x220000 0x80000>;
+						read-only;
+					};
+
+					APPSBLENV@2a0000 {
+						label = "APPSBLENV";
+						reg = <0x2a0000 0x40000>;
+						read-only;
+					};
+
+					OLDART@2e0000 {
+						label = "OLDART";
+						reg = <0x2e0000 0x40000>;
+						read-only;
+					};
+
+					kernel@320000 {
+						label = "kernel";
+						reg = <0x320000 0x200000>;
+					};
+
+					rootfs@520000 {
+						label = "rootfs";
+						reg = <0x520000 0xa60000>;
+					};
+
+					defaultmac: default-mac@0xfaf100 {
+						label = "default-mac";
+						reg = <0xfaf100 0x00200>;
+						read-only;
+					};
+
+					ART@fc0000 {
+						label = "ART";
+						reg = <0xfc0000 0x40000>;
+						read-only;
+					};
+				};
+			};
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			status = "ok";
+		};
+
+		usb30@0 {
+			status = "ok";
+		};
+
+		usb30@1 {
+			status = "ok";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+			force_gen1 = <1>;
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0x6a545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+					>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+			};
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			qcom,id = <1>;
+
+			pinctrl-0 = <&rgmii2_pins>;
+			pinctrl-names = "default";
+
+			mtd-mac-address = <&defaultmac 0>;
+			mtd-mac-address-increment = <1>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+
+			mtd-mac-address = <&defaultmac 0>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		rpm@108000 {
+			pinctrl-0 = <&i2c4_pins>;
+			pinctrl-names = "default";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		wifi {
+			label = "wifi";
+			gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RFKILL>;
+		};
+
+		reset {
+			label = "reset";
+			gpios = <&qcom_pinmux 64 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+
+		wps {
+			label = "wps";
+			gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+		};
+
+		dect {
+			label = "dect";
+			gpios = <&qcom_pinmux 67 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_PHONE>;
+		};
+
+		ledswitch {
+			label = "ledswitch";
+			gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_LIGHTS_TOGGLE>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_pins>;
+		pinctrl-names = "default";
+
+		dsl {
+			label = "vr2600v:white:dsl";
+			gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb {
+			label = "vr2600v:white:usb";
+			gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>;
+		};
+
+		lan {
+			label = "vr2600v:white:lan";
+			gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
+		};
+
+		wlan2g {
+			label = "vr2600v:white:wlan2g";
+			gpios = <&qcom_pinmux 16 GPIO_ACTIVE_HIGH>;
+		};
+
+		wlan5g {
+			label = "vr2600v:white:wlan5g";
+			gpios = <&qcom_pinmux 17 GPIO_ACTIVE_HIGH>;
+		};
+
+		power: power {
+			label = "vr2600v:white:power";
+			gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		phone {
+			label = "vr2600v:white:phone";
+			gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
+		};
+
+		wan {
+			label = "vr2600v:white:wan";
+			gpios = <&qcom_pinmux 56 GPIO_ACTIVE_HIGH>;
+		};
+
+		general: general {
+			label = "vr2600v:white:general";
+			gpios = <&qcom_pinmux 66 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
+
+&adm_dma {
+	status = "ok";
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts
new file mode 100644
index 0000000..9440de5
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064-wpq864.dts
@@ -0,0 +1,570 @@ 
+/*
+ *  BSD LICENSE
+ *
+ *  Copyright (C) 2017 Christian Mehlis <christian@m3hlis.de>
+ *  Copyright (C) 2018 Mathias Kresin <dev@kresin.me>
+ *  All rights reserved.
+ *
+ *  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.
+ *    3. Neither the names of the 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.
+ *
+ *  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.
+ */
+
+#include "qcom-ipq8064-v1.0.dtsi"
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/soc/qcom,tcsr.h>
+
+/ {
+	compatible = "compex,wpq864", "qcom,ipq8064";
+	model = "Compex WPQ864";
+
+	aliases {
+		mdio-gpio0 = &mdio0;
+		serial0 = &gsbi4_serial;
+		ethernet0 = &gmac1;
+		ethernet1 = &gmac0;
+
+		led-boot = &led_pass;
+		led-failsafe = &led_fail;
+		led-running = &led_pass;
+		led-upgrade = &led_pass;
+	};
+
+	chosen {
+		linux,stdout-path = "serial0:115200n8";
+	};
+
+	soc {
+		rpm@108000  {
+			pinctrl-0 = <&rpm_pins>;
+			pinctrl-names = "default";
+		};
+
+		nand@1ac00000 {
+			status = "okay";
+
+			pinctrl-0 = <&nand_pins>;
+			pinctrl-names = "default";
+
+			mt29f2g08abbeah4@0 {
+				compatible = "qcom,nandcs";
+
+				reg = <0>;
+
+				nand-ecc-strength = <4>;
+				nand-bus-width = <8>;
+				nand-ecc-step-size = <512>;
+
+				partitions {
+					compatible = "fixed-partitions";
+					#address-cells = <1>;
+					#size-cells = <1>;
+
+					SBL1@0 {
+						label = "SBL1";
+						reg = <0x0000000 0x0040000>;
+						read-only;
+					};
+
+					MIBIB@40000 {
+						label = "MIBIB";
+						reg = <0x0040000 0x0140000>;
+						read-only;
+					};
+
+					SBL2@180000 {
+						label = "SBL2";
+						reg = <0x0180000 0x0140000>;
+						read-only;
+					};
+
+					SBL3@2c0000 {
+						label = "SBL3";
+						reg = <0x02c0000 0x0280000>;
+						read-only;
+					};
+
+					DDRCONFIG@540000 {
+						label = "DDRCONFIG";
+						reg = <0x0540000 0x0120000>;
+						read-only;
+					};
+
+					SSD@660000 {
+						label = "SSD";
+						reg = <0x0660000 0x0120000>;
+						read-only;
+					};
+
+					TZ@780000 {
+						label = "TZ";
+						reg = <0x0780000 0x0280000>;
+						read-only;
+					};
+
+					RPM@a00000 {
+						label = "RPM";
+						reg = <0x0a00000 0x0280000>;
+						read-only;
+					};
+
+					APPSBL@c80000 {
+						label = "APPSBL";
+						reg = <0x0c80000 0x0500000>;
+						read-only;
+					};
+
+					APPSBLENV@1180000 {
+						label = "APPSBLENV";
+						reg = <0x1180000 0x0080000>;
+					};
+
+					ART@1200000 {
+						label = "ART";
+						reg = <0x1200000 0x0140000>;
+					};
+
+					ubi@1340000 {
+						label = "ubi";
+						reg = <0x1340000 0x4000000>;
+					};
+
+					BOOTCONFIG@1340000 {
+						label = "BOOTCONFIG";
+						reg = <0x5340000 0x0060000>;
+					};
+
+					SBL2-1@53a0000- {
+						label = "SBL2_1";
+						reg = <0x53a0000 0x0140000>;
+						read-only;
+					};
+
+					SBL3-1@54e0000 {
+						label = "SBL3_1";
+						reg = <0x54e0000 0x0280000>;
+						read-only;
+					};
+
+					DDRCONFIG-1@5760000 {
+						label = "DDRCONFIG_1";
+						reg = <0x5760000 0x0120000>;
+						read-only;
+					};
+
+					SSD-1@5880000 {
+						label = "SSD_1";
+						reg = <0x5880000 0x0120000>;
+						read-only;
+					};
+
+					TZ-1@59a0000 {
+						label = "TZ_1";
+						reg = <0x59a0000 0x0280000>;
+						read-only;
+					};
+
+					RPM-1@5c20000 {
+						label = "RPM_1";
+						reg = <0x5c20000 0x0280000>;
+						read-only;
+					};
+
+					BOOTCONFIG1@5ea0000 {
+						label = "BOOTCONFIG1";
+						reg = <0x5ea0000 0x0060000>;
+					};
+
+					APPSBL-1@5f00000 {
+						label = "APPSBL_1";
+						reg = <0x5f00000 0x0500000>;
+						read-only;
+					};
+
+					ubi-1@6400000 {
+						label = "ubi_1";
+						reg = <0x6400000 0x4000000>;
+					};
+
+					unused@a400000 {
+						label = "unused";
+						reg = <0xa400000 0x5c00000>;
+					};
+				};
+			};
+		};
+	};
+
+	mdio0: mdio {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		compatible = "virtual,mdio-gpio";
+
+		pinctrl-0 = <&mdio0_pins>;
+		pinctrl-names = "default";
+
+		gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
+
+		ethernet-phy@0 {
+			device_type = "ethernet-phy";
+			reg = <0>;
+			qca,ar8327-initvals = <
+				0x00004 0x7600000   /* PAD0_MODE */
+				0x00008 0x1000000   /* PAD5_MODE */
+				0x0000c 0x80        /* PAD6_MODE */
+				0x000e4 0x6a545     /* MAC_POWER_SEL */
+				0x000e0 0xc74164de  /* SGMII_CTRL */
+				0x0007c 0x4e        /* PORT0_STATUS */
+				0x00094 0x4e        /* PORT6_STATUS */
+				>;
+		};
+
+		ethernet-phy@4 {
+			device_type = "ethernet-phy";
+			reg = <4>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+
+		pinctrl-0 = <&led_pins>;
+		pinctrl-names = "default";
+
+		rss4 {
+			label = "wpq864:green:rss4";
+			gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>;
+		};
+
+		rss3 {
+			label = "wpq864:green:rss3";
+			gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		rss2 {
+			label = "wpq864:orange:rss2";
+			gpios = <&qcom_pinmux 25 GPIO_ACTIVE_HIGH>;
+		};
+
+		rss1 {
+			label = "wpq864:red:rss1";
+			gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>;
+		};
+
+		led_pass: pass {
+			label = "wpq864:green:pass";
+			gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
+		};
+
+		led_fail: fail {
+			label = "wpq864:green:fail";
+			gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb {
+			label = "wpq864:green:usb";
+			gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb-pcie {
+			label = "wpq864:green:usb-pcie";
+			gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		reset {
+			label = "reset";
+			gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+	};
+
+	beeper {
+		compatible = "gpio-beeper";
+
+		pinctrl-0 = <&beeper_pins>;
+		pinctrl-names = "default";
+
+		gpios = <&qcom_pinmux 55 GPIO_ACTIVE_HIGH>;
+	};
+};
+
+&adm_dma {
+	status = "okay";
+};
+
+&gmac1 {
+	status = "okay";
+
+	pinctrl-0 = <&rgmii2_pins>;
+	pinctrl-names = "default";
+
+	phy-mode = "rgmii";
+	qcom,id = <1>;
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&gmac2 {
+	status = "okay";
+
+	phy-mode = "sgmii";
+	qcom,id = <2>;
+
+	fixed-link {
+		speed = <1000>;
+		full-duplex;
+	};
+};
+
+&gsbi4 {
+	status = "okay";
+	qcom,mode = <GSBI_PROT_I2C_UART>;
+};
+
+&gsbi4_serial {
+	status = "okay";
+
+	pinctrl-0 = <&uart0_pins>;
+	pinctrl-names = "default";
+};
+
+&gsbi5 {
+	status = "okay";
+
+	qcom,mode = <GSBI_PROT_SPI>;
+
+	spi@1a280000 {
+		status = "okay";
+
+		pinctrl-0 = <&spi_pins>;
+		pinctrl-names = "default";
+
+		cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>;
+
+		s25fl256s1@0 {
+			compatible = "jedec,spi-nor";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0>;
+			spi-max-frequency = <50000000>;
+		};
+	};
+};
+
+&hs_phy_0 {		/* USB3 port 0 HS phy */
+	status = "okay";
+};
+
+&hs_phy_1 {		/* USB3 port 1 HS phy */
+	status = "okay";
+};
+
+&ss_phy_0 {		/* USB3 port 0 SS phy */
+	status = "okay";
+
+	rx_eq = <2>;
+	tx_deamp_3_5db = <32>;
+	mpll = <160>;
+};
+
+&ss_phy_1 {		/* USB3 port 1 SS phy */
+	status = "okay";
+
+	rx_eq = <2>;
+	tx_deamp_3_5db = <32>;
+	mpll = <160>;
+};
+
+&pcie0 {
+	status = "okay";
+
+	/delete-property/ pinctrl-0;
+	/delete-property/ pinctrl-names;
+	/delete-property/ perst-gpios;
+};
+
+&pcie1 {
+	status = "okay";
+};
+
+&pcie2 {
+	status = "okay";
+
+	/delete-property/ pinctrl-0;
+	/delete-property/ pinctrl-names;
+	/delete-property/ perst-gpios;
+};
+
+&qcom_pinmux {
+	pinctrl-names = "default";
+	pinctrl-0 = <&state_default>;
+
+	state_default: pinctrl0 {
+		pcie0_pcie2_perst {
+			pins = "gpio3";
+			function = "gpio";
+			drive-strength = <2>;
+			bias-disable;
+			output-high;
+		};
+	};
+
+	led_pins: led_pins {
+		mux {
+			pins = "gpio7", "gpio8", "gpio9",  "gpio22",
+			       "gpio23", "gpio24", "gpio25", "gpio53";
+			function = "gpio";
+			drive-strength = <2>;
+			bias-pull-up;
+		};
+	};
+
+	button_pins: button_pins {
+		mux {
+			pins = "gpio54";
+			function = "gpio";
+			drive-strength = <2>;
+			bias-pull-up;
+		};
+	};
+
+	beeper_pins: beeper_pins {
+		mux {
+			pins = "gpio55";
+			function = "gpio";
+			drive-strength = <2>;
+			bias-pull-up;
+		};
+	};
+
+	rpm_pins: rpm_pins {
+		mux {
+			pins = "gpio12", "gpio13";
+			function = "gsbi4";
+			drive-strength = <10>;
+			bias-disable;
+		};
+	};
+
+	uart0_pins: uart0_pins {
+		mux {
+			pins = "gpio10", "gpio11";
+			function = "gsbi4";
+			drive-strength = <10>;
+			bias-disable;
+		};
+	};
+
+	spi_pins: spi_pins {
+		mux {
+			pins = "gpio18", "gpio19";
+			function = "gsbi5";
+			drive-strength = <10>;
+			bias-pull-down;
+		};
+
+		clk {
+			pins = "gpio21";
+			function = "gsbi5";
+			drive-strength = <12>;
+			bias-pull-down;
+		};
+
+		cs {
+			pins = "gpio20";
+			function = "gpio";
+			drive-strength = <10>;
+			bias-pull-up;
+		};
+	};
+
+	nand_pins: nand_pins {
+		mux {
+			pins = "gpio34", "gpio35", "gpio36", "gpio37",
+			       "gpio38", "gpio39", "gpio40", "gpio41",
+			       "gpio42", "gpio43", "gpio44", "gpio45",
+			       "gpio46", "gpio47";
+			function = "nand";
+			drive-strength = <10>;
+			bias-disable;
+		};
+
+		pullups {
+			pins = "gpio39";
+			bias-pull-up;
+		};
+
+		hold {
+			pins = "gpio40", "gpio41", "gpio42", "gpio43",
+			       "gpio44", "gpio45", "gpio46", "gpio47";
+			bias-bus-hold;
+		};
+	};
+
+	mdio0_pins: mdio0_pins {
+		mux {
+			pins = "gpio0", "gpio1";
+			function = "gpio";
+			drive-strength = <8>;
+			bias-disable;
+		};
+	};
+
+	rgmii2_pins: rgmii2_pins {
+		mux {
+			pins = "gpio27", "gpio28", "gpio29", "gpio30",
+			       "gpio31", "gpio32", "gpio51", "gpio52",
+			       "gpio59", "gpio60", "gpio61", "gpio62";
+			function = "rgmii2";
+			drive-strength = <8>;
+			bias-disable;
+		};
+	};
+};
+
+&usb3_0 {
+	status = "okay";
+};
+
+
+&usb3_1 {
+	status = "okay";
+};
+
+&tcsr {
+	qcom,usb-ctrl-select = <TCSR_USB_SELECT_USB3_DUAL>;
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064.dtsi b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064.dtsi
new file mode 100644
index 0000000..b400991
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -0,0 +1,1333 @@ 
+/dts-v1/;
+
+#include "skeleton.dtsi"
+#include <dt-bindings/clock/qcom,gcc-ipq806x.h>
+#include <dt-bindings/mfd/qcom-rpm.h>
+#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/clock/qcom,lcc-ipq806x.h>
+#include <dt-bindings/soc/qcom,gsbi.h>
+#include <dt-bindings/reset/qcom,gcc-ipq806x.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Qualcomm IPQ8064";
+	compatible = "qcom,ipq8064";
+	interrupt-parent = <&intc>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu@0 {
+			compatible = "qcom,krait";
+			enable-method = "qcom,kpss-acc-v1";
+			device_type = "cpu";
+			reg = <0>;
+			next-level-cache = <&L2>;
+			qcom,acc = <&acc0>;
+			qcom,saw = <&saw0>;
+			clocks = <&kraitcc 0>, <&kraitcc 4>;
+			clock-names = "cpu", "l2";
+			clock-latency = <100000>;
+			cpu-supply = <&smb208_s2a>;
+			voltage-tolerance = <5>;
+			cooling-min-state = <0>;
+			cooling-max-state = <10>;
+			#cooling-cells = <2>;
+			cpu-idle-states = <&CPU_SPC>;
+		};
+
+		cpu1: cpu@1 {
+			compatible = "qcom,krait";
+			enable-method = "qcom,kpss-acc-v1";
+			device_type = "cpu";
+			reg = <1>;
+			next-level-cache = <&L2>;
+			qcom,acc = <&acc1>;
+			qcom,saw = <&saw1>;
+			clocks = <&kraitcc 1>, <&kraitcc 4>;
+			clock-names = "cpu", "l2";
+			clock-latency = <100000>;
+			cpu-supply = <&smb208_s2b>;
+			cooling-min-state = <0>;
+			cooling-max-state = <10>;
+			#cooling-cells = <2>;
+			cpu-idle-states = <&CPU_SPC>;
+		};
+
+		L2: l2-cache {
+			compatible = "cache";
+			cache-level = <2>;
+			qcom,saw = <&saw_l2>;
+		};
+
+		qcom,l2 {
+			qcom,l2-rates = <384000000 1000000000 1200000000>;
+		};
+
+		idle-states {
+			CPU_SPC: spc {
+				compatible = "qcom,idle-state-spc",
+						"arm,idle-state";
+				entry-latency-us = <400>;
+				exit-latency-us = <900>;
+				min-residency-us = <3000>;
+			};
+		};
+	};
+
+	thermal-zones {
+		tsens_tz_sensor0 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 0>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor1 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 1>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor2 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 2>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor3 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 3>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor4 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 4>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor5 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 5>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor6 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 6>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor7 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 7>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor8 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 8>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor9 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 9>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+
+		tsens_tz_sensor10 {
+			polling-delay-passive = <0>;
+			polling-delay = <0>;
+			thermal-sensors = <&tsens 10>;
+
+			trips {
+				cpu-critical-hi {
+					temperature = <125000>;
+					hysteresis = <2000>;
+					type = "critical_high";
+				};
+
+				cpu-config-hi {
+					temperature = <105000>;
+					hysteresis = <2000>;
+					type = "configurable_hi";
+				};
+
+				cpu-config-lo {
+					temperature = <95000>;
+					hysteresis = <2000>;
+					type = "configurable_lo";
+				};
+
+				cpu-critical-low {
+					temperature = <0>;
+					hysteresis = <2000>;
+					type = "critical_low";
+				};
+			};
+		};
+	};
+
+	cpu-pmu {
+		compatible = "qcom,krait-pmu";
+		interrupts = <1 10 0x304>;
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		nss@40000000 {
+			reg = <0x40000000 0x1000000>;
+			no-map;
+		};
+
+		smem: smem@41000000 {
+			reg = <0x41000000 0x200000>;
+			no-map;
+		};
+	};
+
+	clocks {
+		cxo_board {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <25000000>;
+		};
+
+		pxo_board {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <25000000>;
+		};
+
+		sleep_clk: sleep_clk {
+			compatible = "fixed-clock";
+			clock-frequency = <32768>;
+			#clock-cells = <0>;
+		};
+	};
+
+	firmware {
+		scm {
+			compatible = "qcom,scm-ipq806x";
+		};
+	};
+
+	kraitcc: clock-controller {
+		compatible = "qcom,krait-cc-v1";
+		#clock-cells = <1>;
+	};
+
+	qcom,pvs {
+		qcom,pvs-format-a;
+		qcom,speed0-pvs0-bin-v0 =
+			< 1400000000 1250000 >,
+			< 1200000000 1200000 >,
+			< 1000000000 1150000 >,
+			 < 800000000 1100000 >,
+			 < 600000000 1050000 >,
+			 < 384000000 1000000 >;
+
+		qcom,speed0-pvs1-bin-v0 =
+			< 1400000000 1175000 >,
+			< 1200000000 1125000 >,
+			< 1000000000 1075000 >,
+			 < 800000000 1025000 >,
+			 < 600000000  975000 >,
+			 < 384000000  925000 >;
+
+		qcom,speed0-pvs2-bin-v0 =
+			< 1400000000 1125000 >,
+			< 1200000000 1075000 >,
+			< 1000000000 1025000 >,
+			 < 800000000  995000 >,
+			 < 600000000  925000 >,
+			 < 384000000  875000 >;
+
+		qcom,speed0-pvs3-bin-v0 =
+			< 1400000000 1050000 >,
+			< 1200000000 1000000 >,
+			< 1000000000  950000 >,
+			 < 800000000  900000 >,
+			 < 600000000  850000 >,
+			 < 384000000  800000 >;
+	};
+
+	soc: soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "simple-bus";
+
+		lpass@28100000 {
+			compatible = "qcom,lpass-cpu";
+			status = "disabled";
+			clocks = <&lcc AHBIX_CLK>,
+					<&lcc MI2S_OSR_CLK>,
+					<&lcc MI2S_BIT_CLK>;
+			clock-names = "ahbix-clk",
+					"mi2s-osr-clk",
+					"mi2s-bit-clk";
+			interrupts = <0 85 1>;
+			interrupt-names = "lpass-irq-lpaif";
+			reg = <0x28100000 0x10000>;
+			reg-names = "lpass-lpaif";
+		};
+
+		qfprom: qfprom@700000 {
+			compatible = "qcom,qfprom", "syscon";
+			reg = <0x700000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			status = "okay";
+			tsens_calib: calib@400 {
+				reg = <0x400 0x10>;
+			};
+			tsens_backup: backup@410 {
+				reg = <0x410 0x10>;
+			};
+		};
+
+		rpm@108000 {
+			compatible = "qcom,rpm-ipq8064";
+			reg = <0x108000 0x1000>;
+			qcom,ipc = <&l2cc 0x8 2>;
+
+			interrupts = <0 19 0>,
+				     <0 21 0>,
+				     <0 22 0>;
+			interrupt-names = "ack",
+					  "err",
+					  "wakeup";
+
+			clocks = <&gcc RPM_MSG_RAM_H_CLK>;
+			clock-names = "ram";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			rpmcc: clock-controller {
+				compatible	= "qcom,rpmcc-ipq806x", "qcom,rpmcc";
+				#clock-cells = <1>;
+			};
+
+			regulators {
+				compatible = "qcom,rpm-smb208-regulators";
+
+				smb208_s1a: s1a {
+					regulator-min-microvolt = <1050000>;
+					regulator-max-microvolt = <1150000>;
+
+					qcom,switch-mode-frequency = <1200000>;
+
+				};
+
+				smb208_s1b: s1b {
+					regulator-min-microvolt = <1050000>;
+					regulator-max-microvolt = <1150000>;
+
+					qcom,switch-mode-frequency = <1200000>;
+				};
+
+				smb208_s2a: s2a {
+					regulator-min-microvolt = < 800000>;
+					regulator-max-microvolt = <1250000>;
+
+					qcom,switch-mode-frequency = <1200000>;
+				};
+
+				smb208_s2b: s2b {
+					regulator-min-microvolt = < 800000>;
+					regulator-max-microvolt = <1250000>;
+
+					qcom,switch-mode-frequency = <1200000>;
+				};
+			};
+		};
+
+		rng@1a500000 {
+			compatible = "qcom,prng";
+			reg = <0x1a500000 0x200>;
+			clocks = <&gcc PRNG_CLK>;
+			clock-names = "core";
+		};
+
+		qcom_pinmux: pinmux@800000 {
+			compatible = "qcom,ipq8064-pinctrl";
+			reg = <0x800000 0x4000>;
+
+			gpio-controller;
+			#gpio-cells = <2>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			interrupts = <0 16 0x4>;
+
+			pcie0_pins: pcie0_pinmux {
+				mux {
+					pins = "gpio3";
+					function = "pcie1_rst";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			pcie1_pins: pcie1_pinmux {
+				mux {
+					pins = "gpio48";
+					function = "pcie2_rst";
+					drive-strength = <2>;
+					bias-disable;
+				};
+			};
+
+			pcie2_pins: pcie2_pinmux {
+				mux {
+					pins = "gpio63";
+					function = "pcie3_rst";
+					drive-strength = <2>;
+					bias-disable;
+					output-low;
+				};
+			};
+		};
+
+		intc: interrupt-controller@2000000 {
+			compatible = "qcom,msm-qgic2";
+			interrupt-controller;
+			#interrupt-cells = <3>;
+			reg = <0x02000000 0x1000>,
+			      <0x02002000 0x1000>;
+		};
+
+		timer@200a000 {
+			compatible = "qcom,kpss-timer", "qcom,msm-timer";
+			interrupts = <1 1 0x301>,
+				     <1 2 0x301>,
+				     <1 3 0x301>,
+				     <1 4 0x301>,
+				     <1 5 0x301>;
+			reg = <0x0200a000 0x100>;
+			clock-frequency = <25000000>,
+					  <32768>;
+			clocks = <&sleep_clk>;
+			clock-names = "sleep";
+			cpu-offset = <0x80000>;
+		};
+
+		acc0: clock-controller@2088000 {
+			compatible = "qcom,kpss-acc-v1";
+			reg = <0x02088000 0x1000>, <0x02008000 0x1000>;
+			clock-output-names = "acpu0_aux";
+		};
+
+		acc1: clock-controller@2098000 {
+			compatible = "qcom,kpss-acc-v1";
+			reg = <0x02098000 0x1000>, <0x02008000 0x1000>;
+			clock-output-names = "acpu1_aux";
+		};
+
+		l2cc: clock-controller@2011000 {
+			compatible = "qcom,kpss-gcc", "syscon";
+			reg = <0x2011000 0x1000>;
+			clock-output-names = "acpu_l2_aux";
+		};
+
+		saw0: regulator@2089000 {
+			compatible = "qcom,saw2", "syscon";
+			reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
+			regulator;
+		};
+
+		saw1: regulator@2099000 {
+			compatible = "qcom,saw2", "syscon";
+			reg = <0x02099000 0x1000>, <0x02009000 0x1000>;
+			regulator;
+		};
+
+		saw_l2: regulator@02012000 {
+			compatible = "qcom,saw2", "syscon";
+			reg = <0x02012000 0x1000>;
+			regulator;
+		};
+
+		sic_non_secure: sic-non-secure@12100000 {
+			compatible = "syscon";
+			reg = <0x12100000 0x10000>;
+		};
+
+		gsbi2: gsbi@12480000 {
+			compatible = "qcom,gsbi-v1.0.0";
+			cell-index = <2>;
+			reg = <0x12480000 0x100>;
+			clocks = <&gcc GSBI2_H_CLK>;
+			clock-names = "iface";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+			status = "disabled";
+
+			syscon-tcsr = <&tcsr>;
+
+			uart2: serial@12490000 {
+				compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+				reg = <0x12490000 0x1000>,
+				      <0x12480000 0x1000>;
+				interrupts = <0 195 0x0>;
+				clocks = <&gcc GSBI2_UART_CLK>, <&gcc GSBI2_H_CLK>;
+				clock-names = "core", "iface";
+				status = "disabled";
+			};
+
+			i2c@124a0000 {
+				compatible = "qcom,i2c-qup-v1.1.1";
+				reg = <0x124a0000 0x1000>;
+				interrupts = <0 196 0>;
+
+				clocks = <&gcc GSBI2_QUP_CLK>, <&gcc GSBI2_H_CLK>;
+				clock-names = "core", "iface";
+				status = "disabled";
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+		};
+
+		gsbi4: gsbi@16300000 {
+			compatible = "qcom,gsbi-v1.0.0";
+			cell-index = <4>;
+			reg = <0x16300000 0x100>;
+			clocks = <&gcc GSBI4_H_CLK>;
+			clock-names = "iface";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+			status = "disabled";
+
+			syscon-tcsr = <&tcsr>;
+
+			gsbi4_serial: serial@16340000 {
+				compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+				reg = <0x16340000 0x1000>,
+				      <0x16300000 0x1000>;
+				interrupts = <0 152 0x0>;
+				clocks = <&gcc GSBI4_UART_CLK>, <&gcc GSBI4_H_CLK>;
+				clock-names = "core", "iface";
+				status = "disabled";
+			};
+
+			i2c@16380000 {
+				compatible = "qcom,i2c-qup-v1.1.1";
+				reg = <0x16380000 0x1000>;
+				interrupts = <0 153 0>;
+
+				clocks = <&gcc GSBI4_QUP_CLK>, <&gcc GSBI4_H_CLK>;
+				clock-names = "core", "iface";
+				status = "disabled";
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
+		gsbi5: gsbi@1a200000 {
+			compatible = "qcom,gsbi-v1.0.0";
+			cell-index = <5>;
+			reg = <0x1a200000 0x100>;
+			clocks = <&gcc GSBI5_H_CLK>;
+			clock-names = "iface";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+			status = "disabled";
+
+			syscon-tcsr = <&tcsr>;
+
+			uart5: serial@1a240000 {
+				compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
+				reg = <0x1a240000 0x1000>,
+				      <0x1a200000 0x1000>;
+				interrupts = <0 154 0x0>;
+				clocks = <&gcc GSBI5_UART_CLK>, <&gcc GSBI5_H_CLK>;
+				clock-names = "core", "iface";
+				status = "disabled";
+			};
+
+			i2c@1a280000 {
+				compatible = "qcom,i2c-qup-v1.1.1";
+				reg = <0x1a280000 0x1000>;
+				interrupts = <0 155 0>;
+
+				clocks = <&gcc GSBI5_QUP_CLK>, <&gcc GSBI5_H_CLK>;
+				clock-names = "core", "iface";
+				status = "disabled";
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+
+			spi@1a280000 {
+				compatible = "qcom,spi-qup-v1.1.1";
+				reg = <0x1a280000 0x1000>;
+				interrupts = <0 155 0>;
+
+				clocks = <&gcc GSBI5_QUP_CLK>, <&gcc GSBI5_H_CLK>;
+				clock-names = "core", "iface";
+				status = "disabled";
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
+		};
+
+		sata_phy: sata-phy@1b400000 {
+			compatible = "qcom,ipq806x-sata-phy";
+			reg = <0x1b400000 0x200>;
+
+			clocks = <&gcc SATA_PHY_CFG_CLK>;
+			clock-names = "cfg";
+
+			#phy-cells = <0>;
+			status = "disabled";
+		};
+
+		sata@29000000 {
+			compatible = "qcom,ipq806x-ahci", "generic-ahci";
+			reg = <0x29000000 0x180>;
+
+			interrupts = <0 209 0x0>;
+
+			clocks = <&gcc SFAB_SATA_S_H_CLK>,
+				 <&gcc SATA_H_CLK>,
+				 <&gcc SATA_A_CLK>,
+				 <&gcc SATA_RXOOB_CLK>,
+				 <&gcc SATA_PMALIVE_CLK>;
+			clock-names = "slave_face", "iface", "core",
+					"rxoob", "pmalive";
+
+			assigned-clocks = <&gcc SATA_RXOOB_CLK>, <&gcc SATA_PMALIVE_CLK>;
+			assigned-clock-rates = <100000000>, <100000000>;
+
+			phys = <&sata_phy>;
+			phy-names = "sata-phy";
+			status = "disabled";
+		};
+
+		qcom,ssbi@500000 {
+			compatible = "qcom,ssbi";
+			reg = <0x00500000 0x1000>;
+			qcom,controller-type = "pmic-arbiter";
+		};
+
+		gcc: clock-controller@900000 {
+			compatible = "qcom,gcc-ipq8064";
+			reg = <0x00900000 0x4000>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			#power-domain-cells = <1>;
+		};
+
+		tsens: thermal-sensor@900000 {
+			compatible = "qcom,ipq8064-tsens";
+			reg = <0x900000 0x3680>;
+			nvmem-cells = <&tsens_calib>, <&tsens_backup>;
+			nvmem-cell-names = "calib", "calib_backup";
+			interrupts = <0 178 0>;
+			#thermal-sensor-cells = <1>;
+		};
+
+		tcsr: syscon@1a400000 {
+			compatible = "qcom,tcsr-ipq8064", "syscon";
+			reg = <0x1a400000 0x100>;
+		};
+
+		lcc: clock-controller@28000000 {
+			compatible = "qcom,lcc-ipq8064";
+			reg = <0x28000000 0x1000>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+
+		sfpb_mutex_block: syscon@1200600 {
+			compatible = "syscon";
+			reg = <0x01200600 0x100>;
+		};
+
+		hs_phy_1: phy@100f8800 {
+			compatible = "qcom,dwc3-hs-usb-phy";
+			reg = <0x100f8800 0x30>;
+			clocks = <&gcc USB30_1_UTMI_CLK>;
+			clock-names = "ref";
+			#phy-cells = <0>;
+
+			status = "disabled";
+		};
+
+		ss_phy_1: phy@100f8830 {
+			compatible = "qcom,dwc3-ss-usb-phy";
+			reg = <0x100f8830 0x30>;
+			clocks = <&gcc USB30_1_MASTER_CLK>;
+			clock-names = "ref";
+			#phy-cells = <0>;
+
+			status = "disabled";
+		};
+
+		hs_phy_0: phy@110f8800 {
+			compatible = "qcom,dwc3-hs-usb-phy";
+			reg = <0x110f8800 0x30>;
+			clocks = <&gcc USB30_0_UTMI_CLK>;
+			clock-names = "ref";
+			#phy-cells = <0>;
+
+			status = "disabled";
+		};
+
+		ss_phy_0: phy@110f8830 {
+			compatible = "qcom,dwc3-ss-usb-phy";
+			reg = <0x110f8830 0x30>;
+			clocks = <&gcc USB30_0_MASTER_CLK>;
+			clock-names = "ref";
+			#phy-cells = <0>;
+
+			status = "disabled";
+		};
+
+		usb3_0: usb30@0 {
+			compatible = "qcom,dwc3";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clocks = <&gcc USB30_0_MASTER_CLK>;
+			clock-names = "core";
+
+			ranges;
+
+			resets = <&gcc USB30_0_MASTER_RESET>;
+			reset-names = "usb30_0_mstr_rst";
+
+			status = "disabled";
+
+			dwc3@11000000 {
+				compatible = "snps,dwc3";
+				reg = <0x11000000 0xcd00>;
+				interrupts = <0 110 0x4>;
+				phys = <&hs_phy_0>, <&ss_phy_0>;
+				phy-names = "usb2-phy", "usb3-phy";
+				dr_mode = "host";
+				snps,dis_u3_susphy_quirk;
+			};
+		};
+
+		usb3_1: usb30@1 {
+			compatible = "qcom,dwc3";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clocks = <&gcc USB30_1_MASTER_CLK>;
+			clock-names = "core";
+
+			ranges;
+
+			resets = <&gcc USB30_1_MASTER_RESET>;
+			reset-names = "usb30_1_mstr_rst";
+
+			status = "disabled";
+
+			dwc3@10000000 {
+				compatible = "snps,dwc3";
+				reg = <0x10000000 0xcd00>;
+				interrupts = <0 205 0x4>;
+				phys = <&hs_phy_1>, <&ss_phy_1>;
+				phy-names = "usb2-phy", "usb3-phy";
+				dr_mode = "host";
+				snps,dis_u3_susphy_quirk;
+			};
+		};
+
+		pcie0: pci@1b500000 {
+			compatible = "qcom,pcie-ipq8064";
+			reg = <0x1b500000 0x1000
+			       0x1b502000 0x80
+			       0x1b600000 0x100
+			       0x0ff00000 0x100000>;
+			reg-names = "dbi", "elbi", "parf", "config";
+			device_type = "pci";
+			linux,pci-domain = <0>;
+			bus-range = <0x00 0xff>;
+			num-lanes = <1>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+
+			ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00100000   /* downstream I/O */
+				  0x82000000 0 0x08000000 0x08000000 0 0x07e00000>; /* non-prefetchable memory */
+
+			interrupts = <GIC_SPI 35 IRQ_TYPE_NONE>;
+			interrupt-names = "msi";
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0x7>;
+			interrupt-map = <0 0 0 1 &intc 0 36 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
+					<0 0 0 2 &intc 0 37 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
+					<0 0 0 3 &intc 0 38 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
+					<0 0 0 4 &intc 0 39 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
+
+			clocks = <&gcc PCIE_A_CLK>,
+				 <&gcc PCIE_H_CLK>,
+				 <&gcc PCIE_PHY_CLK>,
+				 <&gcc PCIE_AUX_CLK>,
+				 <&gcc PCIE_ALT_REF_CLK>;
+			clock-names = "core", "iface", "phy", "aux", "ref";
+
+			assigned-clocks = <&gcc PCIE_ALT_REF_CLK>;
+			assigned-clock-rates = <100000000>;
+
+			resets = <&gcc PCIE_ACLK_RESET>,
+				 <&gcc PCIE_HCLK_RESET>,
+				 <&gcc PCIE_POR_RESET>,
+				 <&gcc PCIE_PCI_RESET>,
+				 <&gcc PCIE_PHY_RESET>,
+				 <&gcc PCIE_EXT_RESET>;
+			reset-names = "axi", "ahb", "por", "pci", "phy", "ext";
+
+			pinctrl-0 = <&pcie0_pins>;
+			pinctrl-names = "default";
+
+			perst-gpios = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>;
+
+			phy-tx0-term-offset = <7>;
+
+			status = "disabled";
+		};
+
+		pcie1: pci@1b700000 {
+			compatible = "qcom,pcie-ipq8064";
+			reg = <0x1b700000 0x1000
+			       0x1b702000 0x80
+			       0x1b800000 0x100
+			       0x31f00000 0x100000>;
+			reg-names = "dbi", "elbi", "parf", "config";
+			device_type = "pci";
+			linux,pci-domain = <1>;
+			bus-range = <0x00 0xff>;
+			num-lanes = <1>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+
+			ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00100000   /* downstream I/O */
+				  0x82000000 0 0x2e000000 0x2e000000 0 0x03e00000>; /* non-prefetchable memory */
+
+			interrupts = <GIC_SPI 57 IRQ_TYPE_NONE>;
+			interrupt-names = "msi";
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0x7>;
+			interrupt-map = <0 0 0 1 &intc 0 58 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
+					<0 0 0 2 &intc 0 59 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
+					<0 0 0 3 &intc 0 60 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
+					<0 0 0 4 &intc 0 61 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
+
+			clocks = <&gcc PCIE_1_A_CLK>,
+				 <&gcc PCIE_1_H_CLK>,
+				 <&gcc PCIE_1_PHY_CLK>,
+				 <&gcc PCIE_1_AUX_CLK>,
+				 <&gcc PCIE_1_ALT_REF_CLK>;
+			clock-names = "core", "iface", "phy", "aux", "ref";
+
+			assigned-clocks = <&gcc PCIE_1_ALT_REF_CLK>;
+			assigned-clock-rates = <100000000>;
+
+			resets = <&gcc PCIE_1_ACLK_RESET>,
+				 <&gcc PCIE_1_HCLK_RESET>,
+				 <&gcc PCIE_1_POR_RESET>,
+				 <&gcc PCIE_1_PCI_RESET>,
+				 <&gcc PCIE_1_PHY_RESET>,
+				 <&gcc PCIE_1_EXT_RESET>;
+			reset-names = "axi", "ahb", "por", "pci", "phy", "ext";
+
+			pinctrl-0 = <&pcie1_pins>;
+			pinctrl-names = "default";
+
+			perst-gpios = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>;
+
+			phy-tx0-term-offset = <7>;
+
+			status = "disabled";
+		};
+
+		pcie2: pci@1b900000 {
+			compatible = "qcom,pcie-ipq8064";
+			reg = <0x1b900000 0x1000
+			       0x1b902000 0x80
+			       0x1ba00000 0x100
+			       0x35f00000 0x100000>;
+			reg-names = "dbi", "elbi", "parf", "config";
+			device_type = "pci";
+			linux,pci-domain = <2>;
+			bus-range = <0x00 0xff>;
+			num-lanes = <1>;
+			#address-cells = <3>;
+			#size-cells = <2>;
+
+			ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00100000   /* downstream I/O */
+				  0x82000000 0 0x32000000 0x32000000 0 0x03e00000>; /* non-prefetchable memory */
+
+			interrupts = <GIC_SPI 71 IRQ_TYPE_NONE>;
+			interrupt-names = "msi";
+			#interrupt-cells = <1>;
+			interrupt-map-mask = <0 0 0 0x7>;
+			interrupt-map = <0 0 0 1 &intc 0 72 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
+					<0 0 0 2 &intc 0 73 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
+					<0 0 0 3 &intc 0 74 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
+					<0 0 0 4 &intc 0 75 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
+
+			clocks = <&gcc PCIE_2_A_CLK>,
+				 <&gcc PCIE_2_H_CLK>,
+				 <&gcc PCIE_2_PHY_CLK>,
+				 <&gcc PCIE_2_AUX_CLK>,
+				 <&gcc PCIE_2_ALT_REF_CLK>;
+			clock-names = "core", "iface", "phy", "aux", "ref";
+
+			assigned-clocks = <&gcc PCIE_2_ALT_REF_CLK>;
+			assigned-clock-rates = <100000000>;
+
+			resets = <&gcc PCIE_2_ACLK_RESET>,
+				 <&gcc PCIE_2_HCLK_RESET>,
+				 <&gcc PCIE_2_POR_RESET>,
+				 <&gcc PCIE_2_PCI_RESET>,
+				 <&gcc PCIE_2_PHY_RESET>,
+				 <&gcc PCIE_2_EXT_RESET>;
+			reset-names = "axi", "ahb", "por", "pci", "phy", "ext";
+
+			pinctrl-0 = <&pcie2_pins>;
+			pinctrl-names = "default";
+
+			perst-gpios = <&qcom_pinmux 63 GPIO_ACTIVE_LOW>;
+
+			phy-tx0-term-offset = <7>;
+
+			status = "disabled";
+		};
+
+		adm_dma: dma@18300000 {
+			compatible = "qcom,adm";
+			reg = <0x18300000 0x100000>;
+			interrupts = <0 170 0>;
+			#dma-cells = <1>;
+
+			clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>;
+			clock-names = "core", "iface";
+
+			resets = <&gcc ADM0_RESET>,
+				 <&gcc ADM0_PBUS_RESET>,
+				 <&gcc ADM0_C0_RESET>,
+				 <&gcc ADM0_C1_RESET>,
+				 <&gcc ADM0_C2_RESET>;
+			reset-names = "clk", "pbus", "c0", "c1", "c2";
+			qcom,ee = <0>;
+
+			status = "disabled";
+		};
+
+		nand@1ac00000 {
+			compatible = "qcom,ipq806x-nand";
+			reg = <0x1ac00000 0x800>;
+
+			clocks = <&gcc EBI2_CLK>,
+				 <&gcc EBI2_AON_CLK>;
+			clock-names = "core", "aon";
+
+			dmas = <&adm_dma 3>;
+			dma-names = "rxtx";
+			qcom,cmd-crci = <15>;
+			qcom,data-crci = <3>;
+
+			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+
+		nss_common: syscon@03000000 {
+			compatible = "syscon";
+			reg = <0x03000000 0x0000FFFF>;
+		};
+
+		qsgmii_csr: syscon@1bb00000 {
+			compatible = "syscon";
+			reg = <0x1bb00000 0x000001FF>;
+		};
+
+		stmmac_axi_setup: stmmac-axi-config {
+			snps,wr_osr_lmt = <7>;
+			snps,rd_osr_lmt = <7>;
+			snps,blen = <16 0 0 0 0 0 0>;
+		};
+
+		gmac0: ethernet@37000000 {
+			device_type = "network";
+			compatible = "qcom,ipq806x-gmac";
+			reg = <0x37000000 0x200000>;
+			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+
+			snps,axi-config = <&stmmac_axi_setup>;
+			snps,pbl = <32>;
+			snps,aal = <1>;
+
+			qcom,nss-common = <&nss_common>;
+			qcom,qsgmii-csr = <&qsgmii_csr>;
+
+			clocks = <&gcc GMAC_CORE1_CLK>;
+			clock-names = "stmmaceth";
+
+			resets = <&gcc GMAC_CORE1_RESET>;
+			reset-names = "stmmaceth";
+
+			status = "disabled";
+		};
+
+		gmac1: ethernet@37200000 {
+			device_type = "network";
+			compatible = "qcom,ipq806x-gmac";
+			reg = <0x37200000 0x200000>;
+			interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+
+			snps,axi-config = <&stmmac_axi_setup>;
+			snps,pbl = <32>;
+			snps,aal = <1>;
+
+			qcom,nss-common = <&nss_common>;
+			qcom,qsgmii-csr = <&qsgmii_csr>;
+
+			clocks = <&gcc GMAC_CORE2_CLK>;
+			clock-names = "stmmaceth";
+
+			resets = <&gcc GMAC_CORE2_RESET>;
+			reset-names = "stmmaceth";
+
+			status = "disabled";
+		};
+
+		gmac2: ethernet@37400000 {
+			device_type = "network";
+			compatible = "qcom,ipq806x-gmac";
+			reg = <0x37400000 0x200000>;
+			interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+
+			snps,axi-config = <&stmmac_axi_setup>;
+			snps,pbl = <32>;
+			snps,aal = <1>;
+
+			qcom,nss-common = <&nss_common>;
+			qcom,qsgmii-csr = <&qsgmii_csr>;
+
+			clocks = <&gcc GMAC_CORE3_CLK>;
+			clock-names = "stmmaceth";
+
+			resets = <&gcc GMAC_CORE3_RESET>;
+			reset-names = "stmmaceth";
+
+			status = "disabled";
+		};
+
+		gmac3: ethernet@37600000 {
+			device_type = "network";
+			compatible = "qcom,ipq806x-gmac";
+			reg = <0x37600000 0x200000>;
+			interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "macirq";
+
+			snps,axi-config = <&stmmac_axi_setup>;
+			snps,pbl = <32>;
+			snps,aal = <1>;
+
+			qcom,nss-common = <&nss_common>;
+			qcom,qsgmii-csr = <&qsgmii_csr>;
+
+			clocks = <&gcc GMAC_CORE4_CLK>;
+			clock-names = "stmmaceth";
+
+			resets = <&gcc GMAC_CORE4_RESET>;
+			reset-names = "stmmaceth";
+
+			status = "disabled";
+		};
+	};
+
+	sfpb_mutex: sfpb-mutex {
+		compatible = "qcom,sfpb-mutex";
+		syscon = <&sfpb_mutex_block 4 4>;
+
+		#hwlock-cells = <1>;
+	};
+
+	smem {
+		compatible = "qcom,smem";
+		memory-region = <&smem>;
+		hwlocks = <&sfpb_mutex 3>;
+	};
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts
new file mode 100644
index 0000000..2f82979
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-nbg6817.dts
@@ -0,0 +1,393 @@ 
+#include "qcom-ipq8065-v1.0.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "ZyXEL NBG6817";
+	compatible = "zyxel,nbg6817", "qcom,ipq8065";
+
+	memory@0 {
+		reg = <0x42000000 0x1e000000>;
+		device_type = "memory";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+	};
+
+	aliases {
+		serial0 = &gsbi4_serial;
+		mdio-gpio0 = &mdio0;
+		sdcc1 = &sdcc1;
+
+		led-boot = &power;
+		led-failsafe = &power;
+		led-running = &power;
+		led-upgrade = &power;
+	};
+
+	chosen {
+		bootargs = "rootfstype=squashfs,ext4 rootwait noinitrd";
+		linux,stdout-path = "serial0:115200n8";
+		append-rootblock = "root=/dev/mmcblk0p";
+	};
+
+	soc {
+		pinmux@800000 {
+			button_pins: button_pins {
+				mux {
+					pins = "gpio53", "gpio54", "gpio65";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			i2c4_pins: i2c4_pinmux {
+				mux {
+					pins = "gpio12", "gpio13";
+					function = "gsbi4";
+					drive-strength = <12>;
+					bias-disable;
+				};
+			};
+
+			led_pins: led_pins {
+				mux {
+					pins = "gpio9", "gpio26", "gpio33", "gpio64";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-down;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+
+				clk {
+					pins = "gpio1";
+					input-disable;
+				};
+			};
+
+			rgmii2_pins: rgmii2_pins {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+					       "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
+					function = "rgmii2";
+					drive-strength = <8>;
+					bias-disable;
+				};
+
+				tx {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32" ;
+					input-disable;
+				};
+			};
+
+			spi_pins: spi_pins {
+				mux {
+					pins = "gpio18", "gpio19", "gpio21";
+					function = "gsbi5";
+					drive-strength = <10>;
+					bias-none;
+				};
+
+				cs {
+					pins = "gpio20";
+					drive-strength = <12>;
+				};
+			};
+
+			usb0_pwr_en_pins: usb0_pwr_en_pins {
+				mux {
+					pins = "gpio16", "gpio17";
+					function = "gpio";
+					drive-strength = <12>;
+				};
+
+				pwr {
+					pins = "gpio17";
+					bias-pull-down;
+					output-high;
+				};
+
+				ovc {
+					pins = "gpio16";
+					bias-pull-up;
+				};
+			};
+
+			usb1_pwr_en_pins: usb1_pwr_en_pins {
+				mux {
+					pins = "gpio14", "gpio15";
+					function = "gpio";
+					drive-strength = <12>;
+				};
+
+				pwr {
+					pins = "gpio14";
+					bias-pull-down;
+					output-high;
+				};
+
+				ovc {
+					pins = "gpio15";
+					bias-pull-up;
+				};
+			};
+		};
+
+		gsbi@16300000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			serial@16340000 {
+				status = "ok";
+			};
+			/*
+			 * The i2c device on gsbi4 should not be enabled.
+			 * On ipq806x designs gsbi4 i2c is meant for exclusive
+			 * RPM usage. Turning this on in kernel manifests as
+			 * i2c failure for the RPM.
+			 */
+		};
+
+		gsbi5: gsbi@1a200000 {
+			qcom,mode = <GSBI_PROT_SPI>;
+			status = "ok";
+
+			spi4: spi@1a280000 {
+				status = "ok";
+
+				pinctrl-0 = <&spi_pins>;
+				pinctrl-names = "default";
+
+				cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>;
+
+				flash: m25p80@0 {
+					compatible = "jedec,spi-nor";
+					#address-cells = <1>;
+					#size-cells = <1>;
+					spi-max-frequency = <51200000>;
+					reg = <0>;
+
+					partitions {
+						compatible = "qcom,smem";
+					};
+				};
+			};
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			status = "ok";
+		};
+
+		usb30@0 {
+			status = "ok";
+
+			pinctrl-0 = <&usb0_pwr_en_pins>;
+			pinctrl-names = "default";
+		};
+
+		usb30@1 {
+			status = "ok";
+
+			pinctrl-0 = <&usb1_pwr_en_pins>;
+			pinctrl-names = "default";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+			reset-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>;
+			pinctrl-0 = <&pcie0_pins>;
+			pinctrl-names = "default";
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+			reset-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>;
+			pinctrl-0 = <&pcie1_pins>;
+			pinctrl-names = "default";
+			force_gen1 = <1>;
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0xaa545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+					0x00970 0x1e864443  /* QM_PORT0_CTRL0 */
+					0x00974 0x000001c6  /* QM_PORT0_CTRL1 */
+					0x00978 0x19008643  /* QM_PORT1_CTRL0 */
+					0x0097c 0x000001c6  /* QM_PORT1_CTRL1 */
+					0x00980 0x19008643  /* QM_PORT2_CTRL0 */
+					0x00984 0x000001c6  /* QM_PORT2_CTRL1 */
+					0x00988 0x19008643  /* QM_PORT3_CTRL0 */
+					0x0098c 0x000001c6  /* QM_PORT3_CTRL1 */
+					0x00990 0x19008643  /* QM_PORT4_CTRL0 */
+					0x00994 0x000001c6  /* QM_PORT4_CTRL1 */
+					0x00998 0x1e864443  /* QM_PORT5_CTRL0 */
+					0x0099c 0x000001c6  /* QM_PORT5_CTRL1 */
+					0x009a0 0x1e864443  /* QM_PORT6_CTRL0 */
+					0x009a4 0x000001c6  /* QM_PORT6_CTRL1 */
+					>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+				qca,ar8327-initvals = <
+					0x000e4 0x6a545     /* MAC_POWER_SEL */
+					0x0000c 0x80        /* PAD6_MODE */
+					>;
+			};
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			qcom,id = <1>;
+			qcom,phy_mdio_addr = <4>;
+			qcom,poll_required = <0>;
+			qcom,rgmii_delay = <1>;
+			qcom,phy_mii_type = <0>;
+			qcom,emulation = <0>;
+			qcom,irq = <255>;
+			mdiobus = <&mdio0>;
+
+			pinctrl-0 = <&rgmii2_pins>;
+			pinctrl-names = "default";
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+			qcom,phy_mdio_addr = <0>;	/* none */
+			qcom,poll_required = <0>;	/* no polling */
+			qcom,rgmii_delay = <0>;
+			qcom,phy_mii_type = <1>;
+			qcom,emulation = <0>;
+			qcom,irq = <258>;
+			mdiobus = <&mdio0>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		rpm@108000 {
+			pinctrl-0 = <&i2c4_pins>;
+			pinctrl-names = "default";
+		};
+
+		amba {
+			sdcc1: sdcc@12400000 {
+				status = "okay";
+			};
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		wifi {
+			label = "wifi";
+			gpios = <&qcom_pinmux 53 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RFKILL>;
+			linux,input-type = <EV_SW>;
+		};
+
+		reset {
+			label = "reset";
+			gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+		};
+
+		wps {
+			label = "wps";
+			gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_pins>;
+		pinctrl-names = "default";
+
+		internet {
+			label = "nbg6817:white:internet";
+			gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>;
+		};
+
+		power: power {
+			label = "nbg6817:white:power";
+			gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		wifi2g {
+			label = "nbg6817:amber:wifi2g";
+			gpios = <&qcom_pinmux 33 GPIO_ACTIVE_HIGH>;
+		};
+
+		/* wifi2g amber from the manual is missing */
+
+		wifi5g {
+			label = "nbg6817:amber:wifi5g";
+			gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>;
+		};
+
+		/* wifi5g amber from the manual is missing */
+	};
+};
+
+&adm_dma {
+	status = "ok";
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-r7800.dts b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-r7800.dts
new file mode 100644
index 0000000..63cb42a
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-r7800.dts
@@ -0,0 +1,575 @@ 
+#include "qcom-ipq8065-v1.0.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+	model = "Netgear Nighthawk X4S R7800";
+	compatible = "netgear,r7800", "qcom,ipq8065", "qcom,ipq8064";
+
+	memory@0 {
+		reg = <0x42000000 0x1e000000>;
+		device_type = "memory";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		rsvd@41200000 {
+			reg = <0x41200000 0x300000>;
+			no-map;
+		};
+
+		rsvd@5fe00000 {
+			reg = <0x5fe00000 0x200000>;
+			reusable;
+		};
+	};
+
+	aliases {
+		serial0 = &gsbi4_serial;
+		mdio-gpio0 = &mdio0;
+
+		led-boot = &power_white;
+		led-failsafe = &power_amber;
+		led-running = &power_white;
+		led-upgrade = &power_amber;
+	};
+
+	chosen {
+		linux,stdout-path = "serial0:115200n8";
+	};
+
+	soc {
+		pinmux@800000 {
+			button_pins: button_pins {
+				mux {
+					pins = "gpio6", "gpio54", "gpio65";
+					function = "gpio";
+					drive-strength = <2>;
+					bias-pull-up;
+				};
+			};
+
+			i2c4_pins: i2c4_pinmux {
+				mux {
+					pins = "gpio12", "gpio13";
+					function = "gsbi4";
+					drive-strength = <12>;
+					bias-disable;
+				};
+			};
+
+			led_pins: led_pins {
+				pins = "gpio7", "gpio8", "gpio9", "gpio22", "gpio23",
+					"gpio24","gpio26", "gpio53", "gpio64";
+				function = "gpio";
+				drive-strength = <2>;
+				bias-pull-down;
+			};
+
+			nand_pins: nand_pins {
+				mux {
+					pins = "gpio34", "gpio35", "gpio36",
+					       "gpio37", "gpio38", "gpio39",
+					       "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					function = "nand";
+					drive-strength = <10>;
+					bias-disable;
+				};
+				pullups {
+					pins = "gpio39";
+					bias-pull-up;
+				};
+				hold {
+					pins = "gpio40", "gpio41", "gpio42",
+					       "gpio43", "gpio44", "gpio45",
+					       "gpio46", "gpio47";
+					bias-bus-hold;
+				};
+			};
+
+			mdio0_pins: mdio0_pins {
+				mux {
+					pins = "gpio0", "gpio1";
+					function = "gpio";
+					drive-strength = <8>;
+					bias-disable;
+				};
+
+				clk {
+					pins = "gpio1";
+					input-disable;
+				};
+			};
+
+			rgmii2_pins: rgmii2_pins {
+				mux {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+					       "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
+					function = "rgmii2";
+					drive-strength = <8>;
+					bias-disable;
+				};
+
+				tx {
+					pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32" ;
+					input-disable;
+				};
+			};
+
+			spi_pins: spi_pins {
+				mux {
+					pins = "gpio18", "gpio19", "gpio21";
+					function = "gsbi5";
+					bias-pull-down;
+				};
+
+				data {
+					pins = "gpio18", "gpio19";
+					drive-strength = <10>;
+				};
+
+				cs {
+					pins = "gpio20";
+					drive-strength = <10>;
+					bias-pull-up;
+				};
+
+				clk {
+					pins = "gpio21";
+					drive-strength = <12>;
+				};
+			};
+
+			spi6_pins: spi6_pins {
+				mux {
+					pins = "gpio55", "gpio56", "gpio58";
+					function = "gsbi6";
+					bias-pull-down;
+				};
+
+				mosi {
+					pins = "gpio55";
+					drive-strength = <12>;
+				};
+
+				miso {
+					pins = "gpio56";
+					drive-strength = <14>;
+				};
+
+				cs {
+					pins = "gpio57";
+					drive-strength = <12>;
+					bias-pull-up;
+				};
+
+				clk {
+					pins = "gpio58";
+					drive-strength = <12>;
+				};
+
+				reset {
+					pins = "gpio33";
+					drive-strength = <10>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+
+			usb0_pwr_en_pins: usb0_pwr_en_pins {
+				mux {
+					pins = "gpio15";
+					function = "gpio";
+					drive-strength = <12>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+
+			usb1_pwr_en_pins: usb1_pwr_en_pins {
+				mux {
+					pins = "gpio16", "gpio68";
+					function = "gpio";
+					drive-strength = <12>;
+					bias-pull-down;
+					output-high;
+				};
+			};
+		};
+
+		gsbi@16300000 {
+			qcom,mode = <GSBI_PROT_I2C_UART>;
+			status = "ok";
+			serial@16340000 {
+				status = "ok";
+			};
+			/*
+			 * The i2c device on gsbi4 should not be enabled.
+			 * On ipq806x designs gsbi4 i2c is meant for exclusive
+			 * RPM usage. Turning this on in kernel manifests as
+			 * i2c failure for the RPM.
+			 */
+		};
+
+		gsbi5: gsbi@1a200000 {
+			qcom,mode = <GSBI_PROT_SPI>;
+			status = "ok";
+
+			spi5: spi@1a280000 {
+				status = "ok";
+
+				pinctrl-0 = <&spi_pins>;
+				pinctrl-names = "default";
+
+				cs-gpios = <&qcom_pinmux 20 GPIO_ACTIVE_HIGH>;
+
+				flash: m25p80@0 {
+					compatible = "jedec,spi-nor";
+					#address-cells = <1>;
+					#size-cells = <1>;
+					spi-max-frequency = <50000000>;
+					reg = <0>;
+
+					partitions {
+						compatible = "qcom,smem";
+					};
+				};
+			};
+		};
+
+		gsbi6: gsbi@16500000 {
+			qcom,mode = <GSBI_PROT_SPI>;
+			status = "ok";
+			spi6: spi@16580000 {
+				status = "ok";
+
+				pinctrl-0 = <&spi6_pins>;
+				pinctrl-names = "default";
+
+				cs-gpios = <&qcom_pinmux 57 GPIO_ACTIVE_HIGH>;
+
+				spi-nor@0 {
+					compatible = "jedec,spi-nor";
+					reg = <0>;
+					spi-max-frequency = <6000000>;
+				};
+			};
+		};
+
+		sata-phy@1b400000 {
+			status = "ok";
+		};
+
+		sata@29000000 {
+			ports-implemented = <0x1>;
+			status = "ok";
+		};
+
+		phy@100f8800 {		/* USB3 port 1 HS phy */
+			status = "ok";
+		};
+
+		phy@100f8830 {		/* USB3 port 1 SS phy */
+			status = "ok";
+		};
+
+		phy@110f8800 {		/* USB3 port 0 HS phy */
+			status = "ok";
+		};
+
+		phy@110f8830 {		/* USB3 port 0 SS phy */
+			status = "ok";
+		};
+
+		usb30@0 {
+			status = "ok";
+
+			pinctrl-0 = <&usb0_pwr_en_pins>;
+			pinctrl-names = "default";
+		};
+
+		usb30@1 {
+			status = "ok";
+
+			pinctrl-0 = <&usb1_pwr_en_pins>;
+			pinctrl-names = "default";
+		};
+
+		pcie0: pci@1b500000 {
+			status = "ok";
+		};
+
+		pcie1: pci@1b700000 {
+			status = "ok";
+			force_gen1 = <1>;
+		};
+
+		nand@1ac00000 {
+			status = "ok";
+
+			pinctrl-0 = <&nand_pins>;
+			pinctrl-names = "default";
+
+			cs0 {
+				reg = <0>;
+				compatible = "qcom,nandcs";
+
+				nand-ecc-strength = <4>;
+				nand-bus-width = <8>;
+				nand-ecc-step-size = <512>;
+
+				partitions {
+					compatible = "fixed-partitions";
+					#address-cells = <1>;
+					#size-cells = <1>;
+
+					qcadata@0 {
+						label = "qcadata";
+						reg = <0x0000000 0x0c80000>;
+						read-only;
+					};
+
+					APPSBL@c80000 {
+						label = "APPSBL";
+						reg = <0x0c80000 0x0500000>;
+						read-only;
+					};
+
+					APPSBLENV@1180000 {
+						label = "APPSBLENV";
+						reg = <0x1180000 0x0080000>;
+						read-only;
+					};
+
+					art: art@1200000 {
+						label = "art";
+						reg = <0x1200000 0x0140000>;
+						read-only;
+					};
+
+					artbak: art@1340000 {
+						label = "artbak";
+						reg = <0x1340000 0x0140000>;
+						read-only;
+					};
+
+					kernel@1480000 {
+						label = "kernel";
+						reg = <0x1480000 0x0200000>;
+					};
+
+					ubi@1680000 {
+						label = "ubi";
+						reg = <0x1680000 0x1E00000>;
+					};
+
+					netgear@3480000 {
+						label = "netgear";
+						reg = <0x3480000 0x4480000>;
+						read-only;
+					};
+
+					reserve@7900000 {
+						label = "reserve";
+						reg = <0x7900000 0x0700000>;
+						read-only;
+					};
+
+					firmware@1480000 {
+						label = "firmware";
+						reg = <0x1480000 0x2000000>;
+					};
+				};
+			};
+		};
+
+		mdio0: mdio {
+			compatible = "virtual,mdio-gpio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			gpios = <&qcom_pinmux 1 GPIO_ACTIVE_HIGH &qcom_pinmux 0 GPIO_ACTIVE_HIGH>;
+			pinctrl-0 = <&mdio0_pins>;
+			pinctrl-names = "default";
+
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				reg = <0>;
+				qca,ar8327-initvals = <
+					0x00004 0x7600000   /* PAD0_MODE */
+					0x00008 0x1000000   /* PAD5_MODE */
+					0x0000c 0x80        /* PAD6_MODE */
+					0x000e4 0xaa545     /* MAC_POWER_SEL */
+					0x000e0 0xc74164de  /* SGMII_CTRL */
+					0x0007c 0x4e        /* PORT0_STATUS */
+					0x00094 0x4e        /* PORT6_STATUS */
+					0x00970 0x1e864443  /* QM_PORT0_CTRL0 */
+					0x00974 0x000001c6  /* QM_PORT0_CTRL1 */
+					0x00978 0x19008643  /* QM_PORT1_CTRL0 */
+					0x0097c 0x000001c6  /* QM_PORT1_CTRL1 */
+					0x00980 0x19008643  /* QM_PORT2_CTRL0 */
+					0x00984 0x000001c6  /* QM_PORT2_CTRL1 */
+					0x00988 0x19008643  /* QM_PORT3_CTRL0 */
+					0x0098c 0x000001c6  /* QM_PORT3_CTRL1 */
+					0x00990 0x19008643  /* QM_PORT4_CTRL0 */
+					0x00994 0x000001c6  /* QM_PORT4_CTRL1 */
+					0x00998 0x1e864443  /* QM_PORT5_CTRL0 */
+					0x0099c 0x000001c6  /* QM_PORT5_CTRL1 */
+					0x009a0 0x1e864443  /* QM_PORT6_CTRL0 */
+					0x009a4 0x000001c6  /* QM_PORT6_CTRL1 */
+					>;
+				qca,ar8327-vlans = <
+					0x1	0x5e	    /* VLAN1 Ports 1/2/3/4/6 */
+					0x2	0x21	    /* VLAN2 Ports 0/5 */
+				>;
+			};
+
+			phy4: ethernet-phy@4 {
+				device_type = "ethernet-phy";
+				reg = <4>;
+				qca,ar8327-initvals = <
+					0x000e4 0x6a545     /* MAC_POWER_SEL */
+					0x0000c 0x80        /* PAD6_MODE */
+					>;
+			};
+		};
+
+		gmac1: ethernet@37200000 {
+			status = "ok";
+			phy-mode = "rgmii";
+			qcom,id = <1>;
+			qcom,phy_mdio_addr = <4>;
+			qcom,poll_required = <0>;
+			qcom,rgmii_delay = <1>;
+			qcom,phy_mii_type = <0>;
+			qcom,emulation = <0>;
+			qcom,irq = <255>;
+			mdiobus = <&mdio0>;
+
+			pinctrl-0 = <&rgmii2_pins>;
+			pinctrl-names = "default";
+
+			mtd-mac-address = <&art 6>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		gmac2: ethernet@37400000 {
+			status = "ok";
+			phy-mode = "sgmii";
+			qcom,id = <2>;
+			qcom,phy_mdio_addr = <0>;	/* none */
+			qcom,poll_required = <0>;	/* no polling */
+			qcom,rgmii_delay = <0>;
+			qcom,phy_mii_type = <1>;
+			qcom,emulation = <0>;
+			qcom,irq = <258>;
+			mdiobus = <&mdio0>;
+
+			mtd-mac-address = <&art 0>;
+
+			fixed-link {
+				speed = <1000>;
+				full-duplex;
+			};
+		};
+
+		rpm@108000 {
+			pinctrl-0 = <&i2c4_pins>;
+			pinctrl-names = "default";
+		};
+	};
+
+	gpio-keys {
+		compatible = "gpio-keys";
+		pinctrl-0 = <&button_pins>;
+		pinctrl-names = "default";
+
+		wifi {
+			label = "wifi";
+			gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RFKILL>;
+			debounce-interval = <60>;
+			wakeup-source;
+		};
+
+		reset {
+			label = "reset";
+			gpios = <&qcom_pinmux 54 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_RESTART>;
+			debounce-interval = <60>;
+			wakeup-source;
+		};
+
+		wps {
+			label = "wps";
+			gpios = <&qcom_pinmux 65 GPIO_ACTIVE_LOW>;
+			linux,code = <KEY_WPS_BUTTON>;
+			debounce-interval = <60>;
+			wakeup-source;
+		};
+	};
+
+	gpio-leds {
+		compatible = "gpio-leds";
+		pinctrl-0 = <&led_pins>;
+		pinctrl-names = "default";
+
+		power_white: power_white {
+			label = "r7800:white:power";
+			gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
+			default-state = "keep";
+		};
+
+		power_amber: power_amber {
+			label = "r7800:amber:power";
+			gpios = <&qcom_pinmux 9 GPIO_ACTIVE_HIGH>;
+		};
+
+		wan_white {
+			label = "r7800:white:wan";
+			gpios = <&qcom_pinmux 22 GPIO_ACTIVE_HIGH>;
+		};
+
+		wan_amber {
+			label = "r7800:amber:wan";
+			gpios = <&qcom_pinmux 23 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb1 {
+			label = "r7800:white:usb1";
+			gpios = <&qcom_pinmux 7 GPIO_ACTIVE_HIGH>;
+		};
+
+		usb2 {
+			label = "r7800:white:usb2";
+			gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>;
+		};
+
+		esata {
+			label = "r7800:white:esata";
+			gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>;
+		};
+
+		wifi {
+			label = "r7800:white:wifi";
+			gpios = <&qcom_pinmux 64 GPIO_ACTIVE_HIGH>;
+		};
+
+		wps {
+			label = "r7800:white:wps";
+			gpios = <&qcom_pinmux 24 GPIO_ACTIVE_HIGH>;
+		};
+	};
+};
+
+&adm_dma {
+	status = "ok";
+};
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-v1.0.dtsi b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-v1.0.dtsi
new file mode 100644
index 0000000..22b5338
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065-v1.0.dtsi
@@ -0,0 +1 @@ 
+#include "qcom-ipq8065.dtsi"
diff --git a/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065.dtsi b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065.dtsi
new file mode 100644
index 0000000..15f3b95
--- /dev/null
+++ b/target/linux/ipq806x/files-4.14/arch/arm/boot/dts/qcom-ipq8065.dtsi
@@ -0,0 +1,164 @@ 
+#include "qcom-ipq8064.dtsi"
+
+/ {
+	model = "Qualcomm IPQ8065";
+	compatible = "qcom,ipq8065", "qcom,ipq8064";
+
+	qcom,pvs {
+		qcom,pvs-format-a;
+		qcom,speed0-pvs0-bin-v0 =
+			< 1725000000 1262500 >,
+			< 1400000000 1175000 >,
+			< 1000000000 1100000 >,
+			 < 800000000 1050000 >,
+			 < 600000000 1000000 >,
+			 < 384000000 975000 >;
+		qcom,speed0-pvs1-bin-v0 =
+			< 1725000000 1225000 >,
+			< 1400000000 1150000 >,
+			< 1000000000 1075000 >,
+			 < 800000000 1025000 >,
+			 < 600000000 975000 >,
+			 < 384000000 950000 >;
+		qcom,speed0-pvs2-bin-v0 =
+			< 1725000000 1200000 >,
+			< 1400000000 1125000 >,
+			< 1000000000 1050000 >,
+			 < 800000000 1000000 >,
+			 < 600000000 950000 >,
+			 < 384000000 925000 >;
+		qcom,speed0-pvs3-bin-v0 =
+			< 1725000000 1175000 >,
+			< 1400000000 1100000 >,
+			< 1000000000 1025000 >,
+			 < 800000000 975000 >,
+			 < 600000000 925000 >,
+			 < 384000000 900000 >;
+		qcom,speed0-pvs4-bin-v0 =
+			< 1725000000 1150000 >,
+			< 1400000000 1075000 >,
+			< 1000000000 1000000 >,
+			 < 800000000 950000 >,
+			 < 600000000 900000 >,
+			 < 384000000 875000 >;
+		qcom,speed0-pvs5-bin-v0 =
+			< 1725000000 1100000 >,
+			< 1400000000 1025000 >,
+			< 1000000000 950000 >,
+			 < 800000000 900000 >,
+			 < 600000000 850000 >,
+			 < 384000000 825000 >;
+		qcom,speed0-pvs6-bin-v0 =
+			< 1725000000 1050000 >,
+			< 1400000000 975000 >,
+			< 1000000000 900000 >,
+			 < 800000000 850000 >,
+			 < 600000000 800000 >,
+			 < 384000000 775000 >;
+	};
+
+	soc: soc {
+
+		rpm@108000 {
+
+			regulators {
+
+				smb208_s2a: s2a {
+					regulator-min-microvolt = <775000>;
+					regulator-max-microvolt = <1275000>;
+				};
+
+				smb208_s2b: s2b {
+					regulator-min-microvolt = <775000>;
+					regulator-max-microvolt = <1275000>;
+				};
+			};
+		};
+
+		ss_phy_0: phy@110f8830 {
+			rx_eq = <2>;
+			tx_deamp_3_5db = <32>;
+			mpll = <0xa0>;
+		};
+		ss_phy_1: phy@100f8830 {
+			rx_eq = <2>;
+			tx_deamp_3_5db = <32>;
+			mpll = <0xa0>;
+		};
+
+		/* Temporary fixed regulator */
+		vsdcc_fixed: vsdcc-regulator {
+			compatible = "regulator-fixed";
+			regulator-name = "SDCC Power";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-always-on;
+		};
+
+		sdcc1bam:dma@12402000 {
+			compatible = "qcom,bam-v1.3.0";
+			reg = <0x12402000 0x8000>;
+			interrupts = <0 98 0>;
+			clocks = <&gcc SDC1_H_CLK>;
+			clock-names = "bam_clk";
+			#dma-cells = <1>;
+			qcom,ee = <0>;
+                };
+
+		sdcc3bam:dma@12182000 {
+			compatible = "qcom,bam-v1.3.0";
+			reg = <0x12182000 0x8000>;
+			interrupts = <0 96 0>;
+			clocks = <&gcc SDC3_H_CLK>;
+			clock-names = "bam_clk";
+			#dma-cells = <1>;
+			qcom,ee = <0>;
+		};
+
+		amba {
+			compatible = "arm,amba-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+			sdcc1: sdcc@12400000 {
+				status          = "disabled";
+				compatible      = "arm,pl18x", "arm,primecell";
+				arm,primecell-periphid = <0x00051180>;
+				reg             = <0x12400000 0x2000>;
+				interrupts      = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "cmd_irq";
+				clocks          = <&gcc SDC1_CLK>, <&gcc SDC1_H_CLK>;
+				clock-names     = "mclk", "apb_pclk";
+				bus-width       = <8>;
+				max-frequency   = <96000000>;
+				non-removable;
+				cap-sd-highspeed;
+				cap-mmc-highspeed;
+				vmmc-supply = <&vsdcc_fixed>;
+				dmas = <&sdcc1bam 2>, <&sdcc1bam 1>;
+				dma-names = "tx", "rx";
+			};
+
+			sdcc3: sdcc@12180000 {
+				compatible      = "arm,pl18x", "arm,primecell";
+				arm,primecell-periphid = <0x00051180>;
+				status          = "disabled";
+				reg             = <0x12180000 0x2000>;
+				interrupts      = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "cmd_irq";
+				clocks          = <&gcc SDC3_CLK>, <&gcc SDC3_H_CLK>;
+				clock-names     = "mclk", "apb_pclk";
+				bus-width       = <8>;
+				cap-sd-highspeed;
+				cap-mmc-highspeed;
+				max-frequency   = <192000000>;
+				#mmc-ddr-1_8v;
+				sd-uhs-sdr104;
+				sd-uhs-ddr50;
+				vqmmc-supply = <&vsdcc_fixed>;
+				dmas = <&sdcc3bam 2>, <&sdcc3bam 1>;
+				dma-names = "tx", "rx";
+			};
+		};
+	};
+};
diff --git a/target/linux/ipq806x/patches-4.14/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch b/target/linux/ipq806x/patches-4.14/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch
new file mode 100644
index 0000000..da962c7
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0001-dtbindings-qcom_adm-Fix-channel-specifiers.patch
@@ -0,0 +1,71 @@ 
+From 28d0ed88f536dd639adf1b0c7c08e04be3c8f294 Mon Sep 17 00:00:00 2001
+From: Thomas Pedersen <twp@codeaurora.org>
+Date: Mon, 16 May 2016 17:58:50 -0700
+Subject: [PATCH 01/69] dtbindings: qcom_adm: Fix channel specifiers
+
+Original patch from Andy Gross.
+
+This patch removes the crci information from the dma
+channel property.  At least one client device requires
+using more than one CRCI value for a channel.  This does
+not match the current binding and the crci information
+needs to be removed.
+
+Instead, the client device will provide this information
+via other means.
+
+Signed-off-by: Andy Gross <agross@codeaurora.org>
+Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
+---
+ Documentation/devicetree/bindings/dma/qcom_adm.txt | 16 ++++++----------
+ 1 file changed, 6 insertions(+), 10 deletions(-)
+
+--- a/Documentation/devicetree/bindings/dma/qcom_adm.txt
++++ b/Documentation/devicetree/bindings/dma/qcom_adm.txt
+@@ -4,8 +4,7 @@ Required properties:
+ - compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960
+ - reg: Address range for DMA registers
+ - interrupts: Should contain one interrupt shared by all channels
+-- #dma-cells: must be <2>.  First cell denotes the channel number.  Second cell
+-  denotes CRCI (client rate control interface) flow control assignment.
++- #dma-cells: must be <1>.  First cell denotes the channel number.
+ - clocks: Should contain the core clock and interface clock.
+ - clock-names: Must contain "core" for the core clock and "iface" for the
+   interface clock.
+@@ -22,7 +21,7 @@ Example:
+			compatible = "qcom,adm";
+			reg = <0x18300000 0x100000>;
+			interrupts = <0 170 0>;
+-			#dma-cells = <2>;
++			#dma-cells = <1>;
+
+			clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>;
+			clock-names = "core", "iface";
+@@ -35,15 +34,12 @@ Example:
+			qcom,ee = <0>;
+		};
+
+-DMA clients must use the format descripted in the dma.txt file, using a three
++DMA clients must use the format descripted in the dma.txt file, using a two
+ cell specifier for each channel.
+
+-Each dmas request consists of 3 cells:
++Each dmas request consists of two cells:
+  1. phandle pointing to the DMA controller
+  2. channel number
+- 3. CRCI assignment, if applicable.  If no CRCI flow control is required, use 0.
+-    The CRCI is used for flow control.  It identifies the peripheral device that
+-    is the source/destination for the transferred data.
+
+ Example:
+
+@@ -55,7 +51,7 @@ Example:
+
+		cs-gpios = <&qcom_pinmux 20 0>;
+
+-		dmas = <&adm_dma 6 9>,
+-			<&adm_dma 5 10>;
++		dmas = <&adm_dma 6>,
++			<&adm_dma 5>;
+		dma-names = "rx", "tx";
+	};
diff --git a/target/linux/ipq806x/patches-4.14/0002-dmaengine-Add-ADM-driver.patch b/target/linux/ipq806x/patches-4.14/0002-dmaengine-Add-ADM-driver.patch
new file mode 100644
index 0000000..3381ae1
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0002-dmaengine-Add-ADM-driver.patch
@@ -0,0 +1,966 @@ 
+From 563fa24db4e529c5a3311928d73a8a90531ee527 Mon Sep 17 00:00:00 2001
+From: Thomas Pedersen <twp@codeaurora.org>
+Date: Mon, 16 May 2016 17:58:51 -0700
+Subject: [PATCH 02/69] dmaengine: Add ADM driver
+
+Original patch by Andy Gross.
+
+Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA
+controller found in the MSM8x60 and IPQ/APQ8064 platforms.
+
+The ADM supports both memory to memory transactions and memory
+to/from peripheral device transactions.  The controller also provides flow
+control capabilities for transactions to/from peripheral devices.
+
+The initial release of this driver supports slave transfers to/from peripherals
+and also incorporates CRCI (client rate control interface) flow control.
+
+Signed-off-by: Andy Gross <agross@codeaurora.org>
+Signed-off-by: Thomas Pedersen <twp@codeaurora.org>
+---
+ drivers/dma/qcom/Kconfig    |  10 +
+ drivers/dma/qcom/Makefile   |   1 +
+ drivers/dma/qcom/qcom_adm.c | 900 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 911 insertions(+)
+ create mode 100644 drivers/dma/qcom/qcom_adm.c
+
+--- a/drivers/dma/qcom/Kconfig
++++ b/drivers/dma/qcom/Kconfig
+@@ -27,3 +27,13 @@ config QCOM_HIDMA
+	  (user to kernel, kernel to kernel, etc.).  It only supports
+	  memcpy interface. The core is not intended for general
+	  purpose slave DMA.
++
++config QCOM_ADM
++	tristate "Qualcomm ADM support"
++	depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
++	select DMA_ENGINE
++	select DMA_VIRTUAL_CHANNELS
++	---help---
++	  Enable support for the Qualcomm ADM DMA controller.  This controller
++	  provides DMA capabilities for both general purpose and on-chip
++	  peripheral devices.
+--- a/drivers/dma/qcom/Makefile
++++ b/drivers/dma/qcom/Makefile
+@@ -4,3 +4,4 @@ obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mg
+ hdma_mgmt-objs	 := hidma_mgmt.o hidma_mgmt_sys.o
+ obj-$(CONFIG_QCOM_HIDMA) +=  hdma.o
+ hdma-objs        := hidma_ll.o hidma.o hidma_dbg.o
++obj-$(CONFIG_QCOM_ADM) += qcom_adm.o
+--- /dev/null
++++ b/drivers/dma/qcom/qcom_adm.c
+@@ -0,0 +1,914 @@
++/*
++ * Copyright (c) 2013-2015, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/dma-mapping.h>
++#include <linux/scatterlist.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/of_irq.h>
++#include <linux/of_dma.h>
++#include <linux/reset.h>
++#include <linux/clk.h>
++#include <linux/dmaengine.h>
++
++#include "../dmaengine.h"
++#include "../virt-dma.h"
++
++/* ADM registers - calculated from channel number and security domain */
++#define ADM_CHAN_MULTI			0x4
++#define ADM_CI_MULTI			0x4
++#define ADM_CRCI_MULTI			0x4
++#define ADM_EE_MULTI			0x800
++#define ADM_CHAN_OFFS(chan)		(ADM_CHAN_MULTI * chan)
++#define ADM_EE_OFFS(ee)			(ADM_EE_MULTI * ee)
++#define ADM_CHAN_EE_OFFS(chan, ee)	(ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee))
++#define ADM_CHAN_OFFS(chan)		(ADM_CHAN_MULTI * chan)
++#define ADM_CI_OFFS(ci)			(ADM_CHAN_OFF(ci))
++#define ADM_CH_CMD_PTR(chan, ee)	(ADM_CHAN_EE_OFFS(chan, ee))
++#define ADM_CH_RSLT(chan, ee)		(0x40 + ADM_CHAN_EE_OFFS(chan, ee))
++#define ADM_CH_FLUSH_STATE0(chan, ee)	(0x80 + ADM_CHAN_EE_OFFS(chan, ee))
++#define ADM_CH_STATUS_SD(chan, ee)	(0x200 + ADM_CHAN_EE_OFFS(chan, ee))
++#define ADM_CH_CONF(chan)		(0x240 + ADM_CHAN_OFFS(chan))
++#define ADM_CH_RSLT_CONF(chan, ee)	(0x300 + ADM_CHAN_EE_OFFS(chan, ee))
++#define ADM_SEC_DOMAIN_IRQ_STATUS(ee)	(0x380 + ADM_EE_OFFS(ee))
++#define ADM_CI_CONF(ci)			(0x390 + ci * ADM_CI_MULTI)
++#define ADM_GP_CTL			0x3d8
++#define ADM_CRCI_CTL(crci, ee)		(0x400 + crci * ADM_CRCI_MULTI + \
++						ADM_EE_OFFS(ee))
++
++/* channel status */
++#define ADM_CH_STATUS_VALID	BIT(1)
++
++/* channel result */
++#define ADM_CH_RSLT_VALID	BIT(31)
++#define ADM_CH_RSLT_ERR		BIT(3)
++#define ADM_CH_RSLT_FLUSH	BIT(2)
++#define ADM_CH_RSLT_TPD		BIT(1)
++
++/* channel conf */
++#define ADM_CH_CONF_SHADOW_EN		BIT(12)
++#define ADM_CH_CONF_MPU_DISABLE		BIT(11)
++#define ADM_CH_CONF_PERM_MPU_CONF	BIT(9)
++#define ADM_CH_CONF_FORCE_RSLT_EN	BIT(7)
++#define ADM_CH_CONF_SEC_DOMAIN(ee)	(((ee & 0x3) << 4) | ((ee & 0x4) << 11))
++
++/* channel result conf */
++#define ADM_CH_RSLT_CONF_FLUSH_EN	BIT(1)
++#define ADM_CH_RSLT_CONF_IRQ_EN		BIT(0)
++
++/* CRCI CTL */
++#define ADM_CRCI_CTL_MUX_SEL	BIT(18)
++#define ADM_CRCI_CTL_RST	BIT(17)
++
++/* CI configuration */
++#define ADM_CI_RANGE_END(x)	(x << 24)
++#define ADM_CI_RANGE_START(x)	(x << 16)
++#define ADM_CI_BURST_4_WORDS	BIT(2)
++#define ADM_CI_BURST_8_WORDS	BIT(3)
++
++/* GP CTL */
++#define ADM_GP_CTL_LP_EN	BIT(12)
++#define ADM_GP_CTL_LP_CNT(x)	(x << 8)
++
++/* Command pointer list entry */
++#define ADM_CPLE_LP		BIT(31)
++#define ADM_CPLE_CMD_PTR_LIST	BIT(29)
++
++/* Command list entry */
++#define ADM_CMD_LC		BIT(31)
++#define ADM_CMD_DST_CRCI(n)	(((n) & 0xf) << 7)
++#define ADM_CMD_SRC_CRCI(n)	(((n) & 0xf) << 3)
++
++#define ADM_CMD_TYPE_SINGLE	0x0
++#define ADM_CMD_TYPE_BOX	0x3
++
++#define ADM_CRCI_MUX_SEL	BIT(4)
++#define ADM_DESC_ALIGN		8
++#define ADM_MAX_XFER		(SZ_64K-1)
++#define ADM_MAX_ROWS		(SZ_64K-1)
++#define ADM_MAX_CHANNELS	16
++
++struct adm_desc_hw_box {
++	u32 cmd;
++	u32 src_addr;
++	u32 dst_addr;
++	u32 row_len;
++	u32 num_rows;
++	u32 row_offset;
++};
++
++struct adm_desc_hw_single {
++	u32 cmd;
++	u32 src_addr;
++	u32 dst_addr;
++	u32 len;
++};
++
++struct adm_async_desc {
++	struct virt_dma_desc vd;
++	struct adm_device *adev;
++
++	size_t length;
++	enum dma_transfer_direction dir;
++	dma_addr_t dma_addr;
++	size_t dma_len;
++
++	void *cpl;
++	dma_addr_t cp_addr;
++	u32 crci;
++	u32 mux;
++	u32 blk_size;
++};
++
++struct adm_chan {
++	struct virt_dma_chan vc;
++	struct adm_device *adev;
++
++	/* parsed from DT */
++	u32 id;			/* channel id */
++
++	struct adm_async_desc *curr_txd;
++	struct dma_slave_config slave;
++	struct list_head node;
++
++	int error;
++	int initialized;
++};
++
++static inline struct adm_chan *to_adm_chan(struct dma_chan *common)
++{
++	return container_of(common, struct adm_chan, vc.chan);
++}
++
++struct adm_device {
++	void __iomem *regs;
++	struct device *dev;
++	struct dma_device common;
++	struct device_dma_parameters dma_parms;
++	struct adm_chan *channels;
++
++	u32 ee;
++
++	struct clk *core_clk;
++	struct clk *iface_clk;
++
++	struct reset_control *clk_reset;
++	struct reset_control *c0_reset;
++	struct reset_control *c1_reset;
++	struct reset_control *c2_reset;
++	int irq;
++};
++
++/**
++ * adm_free_chan - Frees dma resources associated with the specific channel
++ *
++ * Free all allocated descriptors associated with this channel
++ *
++ */
++static void adm_free_chan(struct dma_chan *chan)
++{
++	/* free all queued descriptors */
++	vchan_free_chan_resources(to_virt_chan(chan));
++}
++
++/**
++ * adm_get_blksize - Get block size from burst value
++ *
++ */
++static int adm_get_blksize(unsigned int burst)
++{
++	int ret;
++
++	switch (burst) {
++	case 16:
++	case 32:
++	case 64:
++	case 128:
++		ret = ffs(burst>>4) - 1;
++		break;
++	case 192:
++		ret = 4;
++		break;
++	case 256:
++		ret = 5;
++		break;
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
++/**
++ * adm_process_fc_descriptors - Process descriptors for flow controlled xfers
++ *
++ * @achan: ADM channel
++ * @desc: Descriptor memory pointer
++ * @sg: Scatterlist entry
++ * @crci: CRCI value
++ * @burst: Burst size of transaction
++ * @direction: DMA transfer direction
++ */
++static void *adm_process_fc_descriptors(struct adm_chan *achan,
++	void *desc, struct scatterlist *sg, u32 crci, u32 burst,
++	enum dma_transfer_direction direction)
++{
++	struct adm_desc_hw_box *box_desc = NULL;
++	struct adm_desc_hw_single *single_desc;
++	u32 remainder = sg_dma_len(sg);
++	u32 rows, row_offset, crci_cmd;
++	u32 mem_addr = sg_dma_address(sg);
++	u32 *incr_addr = &mem_addr;
++	u32 *src, *dst;
++
++	if (direction == DMA_DEV_TO_MEM) {
++		crci_cmd = ADM_CMD_SRC_CRCI(crci);
++		row_offset = burst;
++		src = &achan->slave.src_addr;
++		dst = &mem_addr;
++	} else {
++		crci_cmd = ADM_CMD_DST_CRCI(crci);
++		row_offset = burst << 16;
++		src = &mem_addr;
++		dst = &achan->slave.dst_addr;
++	}
++
++	while (remainder >= burst) {
++		box_desc = desc;
++		box_desc->cmd = ADM_CMD_TYPE_BOX | crci_cmd;
++		box_desc->row_offset = row_offset;
++		box_desc->src_addr = *src;
++		box_desc->dst_addr = *dst;
++
++		rows = remainder / burst;
++		rows = min_t(u32, rows, ADM_MAX_ROWS);
++		box_desc->num_rows = rows << 16 | rows;
++		box_desc->row_len = burst << 16 | burst;
++
++		*incr_addr += burst * rows;
++		remainder -= burst * rows;
++		desc += sizeof(*box_desc);
++	}
++
++	/* if leftover bytes, do one single descriptor */
++	if (remainder) {
++		single_desc = desc;
++		single_desc->cmd = ADM_CMD_TYPE_SINGLE | crci_cmd;
++		single_desc->len = remainder;
++		single_desc->src_addr = *src;
++		single_desc->dst_addr = *dst;
++		desc += sizeof(*single_desc);
++
++		if (sg_is_last(sg))
++			single_desc->cmd |= ADM_CMD_LC;
++	} else {
++		if (box_desc && sg_is_last(sg))
++			box_desc->cmd |= ADM_CMD_LC;
++	}
++
++	return desc;
++}
++
++/**
++ * adm_process_non_fc_descriptors - Process descriptors for non-fc xfers
++ *
++ * @achan: ADM channel
++ * @desc: Descriptor memory pointer
++ * @sg: Scatterlist entry
++ * @direction: DMA transfer direction
++ */
++static void *adm_process_non_fc_descriptors(struct adm_chan *achan,
++	void *desc, struct scatterlist *sg,
++	enum dma_transfer_direction direction)
++{
++	struct adm_desc_hw_single *single_desc;
++	u32 remainder = sg_dma_len(sg);
++	u32 mem_addr = sg_dma_address(sg);
++	u32 *incr_addr = &mem_addr;
++	u32 *src, *dst;
++
++	if (direction == DMA_DEV_TO_MEM) {
++		src = &achan->slave.src_addr;
++		dst = &mem_addr;
++	} else {
++		src = &mem_addr;
++		dst = &achan->slave.dst_addr;
++	}
++
++	do {
++		single_desc = desc;
++		single_desc->cmd = ADM_CMD_TYPE_SINGLE;
++		single_desc->src_addr = *src;
++		single_desc->dst_addr = *dst;
++		single_desc->len = (remainder > ADM_MAX_XFER) ?
++				ADM_MAX_XFER : remainder;
++
++		remainder -= single_desc->len;
++		*incr_addr += single_desc->len;
++		desc += sizeof(*single_desc);
++	} while (remainder);
++
++	/* set last command if this is the end of the whole transaction */
++	if (sg_is_last(sg))
++		single_desc->cmd |= ADM_CMD_LC;
++
++	return desc;
++}
++
++/**
++ * adm_prep_slave_sg - Prep slave sg transaction
++ *
++ * @chan: dma channel
++ * @sgl: scatter gather list
++ * @sg_len: length of sg
++ * @direction: DMA transfer direction
++ * @flags: DMA flags
++ * @context: transfer context (unused)
++ */
++static struct dma_async_tx_descriptor *adm_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 adm_chan *achan = to_adm_chan(chan);
++	struct adm_device *adev = achan->adev;
++	struct adm_async_desc *async_desc;
++	struct scatterlist *sg;
++	dma_addr_t cple_addr;
++	u32 i, burst;
++	u32 single_count = 0, box_count = 0, crci = 0;
++	void *desc;
++	u32 *cple;
++	int blk_size = 0;
++
++	if (!is_slave_direction(direction)) {
++		dev_err(adev->dev, "invalid dma direction\n");
++		return NULL;
++	}
++
++	/*
++	 * get burst value from slave configuration
++	 */
++	burst = (direction == DMA_MEM_TO_DEV) ?
++		achan->slave.dst_maxburst :
++		achan->slave.src_maxburst;
++
++	/* if using flow control, validate burst and crci values */
++	if (achan->slave.device_fc) {
++
++		blk_size = adm_get_blksize(burst);
++		if (blk_size < 0) {
++			dev_err(adev->dev, "invalid burst value: %d\n",
++				burst);
++			return ERR_PTR(-EINVAL);
++		}
++
++		crci = achan->slave.slave_id & 0xf;
++		if (!crci || achan->slave.slave_id > 0x1f) {
++			dev_err(adev->dev, "invalid crci value\n");
++			return ERR_PTR(-EINVAL);
++		}
++	}
++
++	/* iterate through sgs and compute allocation size of structures */
++	for_each_sg(sgl, sg, sg_len, i) {
++		if (achan->slave.device_fc) {
++			box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst,
++						  ADM_MAX_ROWS);
++			if (sg_dma_len(sg) % burst)
++				single_count++;
++		} else {
++			single_count += DIV_ROUND_UP(sg_dma_len(sg),
++						     ADM_MAX_XFER);
++		}
++	}
++
++	async_desc = kzalloc(sizeof(*async_desc), GFP_ATOMIC);
++	if (!async_desc)
++		return ERR_PTR(-ENOMEM);
++
++	if (crci)
++		async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ?
++					ADM_CRCI_CTL_MUX_SEL : 0;
++	async_desc->crci = crci;
++	async_desc->blk_size = blk_size;
++	async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) +
++				box_count * sizeof(struct adm_desc_hw_box) +
++				sizeof(*cple) + 2 * ADM_DESC_ALIGN;
++
++	async_desc->cpl = kzalloc(async_desc->dma_len, GFP_ATOMIC);
++	if (!async_desc->cpl)
++		goto free;
++
++	async_desc->adev = adev;
++
++	/* both command list entry and descriptors must be 8 byte aligned */
++	cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN);
++	desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN);
++
++	for_each_sg(sgl, sg, sg_len, i) {
++		async_desc->length += sg_dma_len(sg);
++
++		if (achan->slave.device_fc)
++			desc = adm_process_fc_descriptors(achan, desc, sg, crci,
++							burst, direction);
++		else
++			desc = adm_process_non_fc_descriptors(achan, desc, sg,
++							   direction);
++	}
++
++	async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl,
++					      async_desc->dma_len,
++					      DMA_TO_DEVICE);
++	if (dma_mapping_error(adev->dev, async_desc->dma_addr))
++		goto free;
++
++	cple_addr = async_desc->dma_addr + ((void *)cple - async_desc->cpl);
++
++	/* init cmd list */
++	dma_sync_single_for_cpu(adev->dev, cple_addr, sizeof(*cple),
++				DMA_TO_DEVICE);
++	*cple = ADM_CPLE_LP;
++	*cple |= (async_desc->dma_addr + ADM_DESC_ALIGN) >> 3;
++	dma_sync_single_for_device(adev->dev, cple_addr, sizeof(*cple),
++				   DMA_TO_DEVICE);
++
++	return vchan_tx_prep(&achan->vc, &async_desc->vd, flags);
++
++free:
++	kfree(async_desc);
++	return ERR_PTR(-ENOMEM);
++}
++
++/**
++ * adm_terminate_all - terminate all transactions on a channel
++ * @achan: adm dma channel
++ *
++ * Dequeues and frees all transactions, aborts current transaction
++ * No callbacks are done
++ *
++ */
++static int adm_terminate_all(struct dma_chan *chan)
++{
++	struct adm_chan *achan = to_adm_chan(chan);
++	struct adm_device *adev = achan->adev;
++	unsigned long flags;
++	LIST_HEAD(head);
++
++	spin_lock_irqsave(&achan->vc.lock, flags);
++	vchan_get_all_descriptors(&achan->vc, &head);
++
++	/* send flush command to terminate current transaction */
++	writel_relaxed(0x0,
++		adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee));
++
++	spin_unlock_irqrestore(&achan->vc.lock, flags);
++
++	vchan_dma_desc_free_list(&achan->vc, &head);
++
++	return 0;
++}
++
++static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg)
++{
++	struct adm_chan *achan = to_adm_chan(chan);
++	unsigned long flag;
++
++	spin_lock_irqsave(&achan->vc.lock, flag);
++	memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config));
++	spin_unlock_irqrestore(&achan->vc.lock, flag);
++
++	return 0;
++}
++
++/**
++ * adm_start_dma - start next transaction
++ * @achan - ADM dma channel
++ */
++static void adm_start_dma(struct adm_chan *achan)
++{
++	struct virt_dma_desc *vd = vchan_next_desc(&achan->vc);
++	struct adm_device *adev = achan->adev;
++	struct adm_async_desc *async_desc;
++
++	lockdep_assert_held(&achan->vc.lock);
++
++	if (!vd)
++		return;
++
++	list_del(&vd->node);
++
++	/* write next command list out to the CMD FIFO */
++	async_desc = container_of(vd, struct adm_async_desc, vd);
++	achan->curr_txd = async_desc;
++
++	/* reset channel error */
++	achan->error = 0;
++
++	if (!achan->initialized) {
++		/* enable interrupts */
++		writel(ADM_CH_CONF_SHADOW_EN |
++		       ADM_CH_CONF_PERM_MPU_CONF |
++		       ADM_CH_CONF_MPU_DISABLE |
++		       ADM_CH_CONF_SEC_DOMAIN(adev->ee),
++		       adev->regs + ADM_CH_CONF(achan->id));
++
++		writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN,
++			adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
++
++		achan->initialized = 1;
++	}
++
++	/* set the crci block size if this transaction requires CRCI */
++	if (async_desc->crci) {
++		writel(async_desc->mux | async_desc->blk_size,
++			adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee));
++	}
++
++	/* make sure IRQ enable doesn't get reordered */
++	wmb();
++
++	/* write next command list out to the CMD FIFO */
++	writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3,
++		adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee));
++}
++
++/**
++ * adm_dma_irq - irq handler for ADM controller
++ * @irq: IRQ of interrupt
++ * @data: callback data
++ *
++ * IRQ handler for the bam controller
++ */
++static irqreturn_t adm_dma_irq(int irq, void *data)
++{
++	struct adm_device *adev = data;
++	u32 srcs, i;
++	struct adm_async_desc *async_desc;
++	unsigned long flags;
++
++	srcs = readl_relaxed(adev->regs +
++			ADM_SEC_DOMAIN_IRQ_STATUS(adev->ee));
++
++	for (i = 0; i < ADM_MAX_CHANNELS; i++) {
++		struct adm_chan *achan = &adev->channels[i];
++		u32 status, result;
++
++		if (srcs & BIT(i)) {
++			status = readl_relaxed(adev->regs +
++				ADM_CH_STATUS_SD(i, adev->ee));
++
++			/* if no result present, skip */
++			if (!(status & ADM_CH_STATUS_VALID))
++				continue;
++
++			result = readl_relaxed(adev->regs +
++				ADM_CH_RSLT(i, adev->ee));
++
++			/* no valid results, skip */
++			if (!(result & ADM_CH_RSLT_VALID))
++				continue;
++
++			/* flag error if transaction was flushed or failed */
++			if (result & (ADM_CH_RSLT_ERR | ADM_CH_RSLT_FLUSH))
++				achan->error = 1;
++
++			spin_lock_irqsave(&achan->vc.lock, flags);
++			async_desc = achan->curr_txd;
++
++			achan->curr_txd = NULL;
++
++			if (async_desc) {
++				vchan_cookie_complete(&async_desc->vd);
++
++				/* kick off next DMA */
++				adm_start_dma(achan);
++			}
++
++			spin_unlock_irqrestore(&achan->vc.lock, flags);
++		}
++	}
++
++	return IRQ_HANDLED;
++}
++
++/**
++ * adm_tx_status - returns status of transaction
++ * @chan: dma channel
++ * @cookie: transaction cookie
++ * @txstate: DMA transaction state
++ *
++ * Return status of dma transaction
++ */
++static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
++	struct dma_tx_state *txstate)
++{
++	struct adm_chan *achan = to_adm_chan(chan);
++	struct virt_dma_desc *vd;
++	enum dma_status ret;
++	unsigned long flags;
++	size_t residue = 0;
++
++	ret = dma_cookie_status(chan, cookie, txstate);
++	if (ret == DMA_COMPLETE || !txstate)
++		return ret;
++
++	spin_lock_irqsave(&achan->vc.lock, flags);
++
++	vd = vchan_find_desc(&achan->vc, cookie);
++	if (vd)
++		residue = container_of(vd, struct adm_async_desc, vd)->length;
++
++	spin_unlock_irqrestore(&achan->vc.lock, flags);
++
++	/*
++	 * residue is either the full length if it is in the issued list, or 0
++	 * if it is in progress.  We have no reliable way of determining
++	 * anything inbetween
++	*/
++	dma_set_residue(txstate, residue);
++
++	if (achan->error)
++		return DMA_ERROR;
++
++	return ret;
++}
++
++/**
++ * adm_issue_pending - starts pending transactions
++ * @chan: dma channel
++ *
++ * Issues all pending transactions and starts DMA
++ */
++static void adm_issue_pending(struct dma_chan *chan)
++{
++	struct adm_chan *achan = to_adm_chan(chan);
++	unsigned long flags;
++
++	spin_lock_irqsave(&achan->vc.lock, flags);
++
++	if (vchan_issue_pending(&achan->vc) && !achan->curr_txd)
++		adm_start_dma(achan);
++	spin_unlock_irqrestore(&achan->vc.lock, flags);
++}
++
++/**
++ * adm_dma_free_desc - free descriptor memory
++ * @vd: virtual descriptor
++ *
++ */
++static void adm_dma_free_desc(struct virt_dma_desc *vd)
++{
++	struct adm_async_desc *async_desc = container_of(vd,
++			struct adm_async_desc, vd);
++
++	dma_unmap_single(async_desc->adev->dev, async_desc->dma_addr,
++			 async_desc->dma_len, DMA_TO_DEVICE);
++	kfree(async_desc->cpl);
++	kfree(async_desc);
++}
++
++static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan,
++	u32 index)
++{
++	achan->id = index;
++	achan->adev = adev;
++
++	vchan_init(&achan->vc, &adev->common);
++	achan->vc.desc_free = adm_dma_free_desc;
++}
++
++static int adm_dma_probe(struct platform_device *pdev)
++{
++	struct adm_device *adev;
++	struct resource *iores;
++	int ret;
++	u32 i;
++
++	adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL);
++	if (!adev)
++		return -ENOMEM;
++
++	adev->dev = &pdev->dev;
++
++	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	adev->regs = devm_ioremap_resource(&pdev->dev, iores);
++	if (IS_ERR(adev->regs))
++		return PTR_ERR(adev->regs);
++
++	adev->irq = platform_get_irq(pdev, 0);
++	if (adev->irq < 0)
++		return adev->irq;
++
++	ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &adev->ee);
++	if (ret) {
++		dev_err(adev->dev, "Execution environment unspecified\n");
++		return ret;
++	}
++
++	adev->core_clk = devm_clk_get(adev->dev, "core");
++	if (IS_ERR(adev->core_clk))
++		return PTR_ERR(adev->core_clk);
++
++	ret = clk_prepare_enable(adev->core_clk);
++	if (ret) {
++		dev_err(adev->dev, "failed to prepare/enable core clock\n");
++		return ret;
++	}
++
++	adev->iface_clk = devm_clk_get(adev->dev, "iface");
++	if (IS_ERR(adev->iface_clk)) {
++		ret = PTR_ERR(adev->iface_clk);
++		goto err_disable_core_clk;
++	}
++
++	ret = clk_prepare_enable(adev->iface_clk);
++	if (ret) {
++		dev_err(adev->dev, "failed to prepare/enable iface clock\n");
++		goto err_disable_core_clk;
++	}
++
++	adev->clk_reset = devm_reset_control_get(&pdev->dev, "clk");
++	if (IS_ERR(adev->clk_reset)) {
++		dev_err(adev->dev, "failed to get ADM0 reset\n");
++		ret = PTR_ERR(adev->clk_reset);
++		goto err_disable_clks;
++	}
++
++	adev->c0_reset = devm_reset_control_get(&pdev->dev, "c0");
++	if (IS_ERR(adev->c0_reset)) {
++		dev_err(adev->dev, "failed to get ADM0 C0 reset\n");
++		ret = PTR_ERR(adev->c0_reset);
++		goto err_disable_clks;
++	}
++
++	adev->c1_reset = devm_reset_control_get(&pdev->dev, "c1");
++	if (IS_ERR(adev->c1_reset)) {
++		dev_err(adev->dev, "failed to get ADM0 C1 reset\n");
++		ret = PTR_ERR(adev->c1_reset);
++		goto err_disable_clks;
++	}
++
++	adev->c2_reset = devm_reset_control_get(&pdev->dev, "c2");
++	if (IS_ERR(adev->c2_reset)) {
++		dev_err(adev->dev, "failed to get ADM0 C2 reset\n");
++		ret = PTR_ERR(adev->c2_reset);
++		goto err_disable_clks;
++	}
++
++	reset_control_assert(adev->clk_reset);
++	reset_control_assert(adev->c0_reset);
++	reset_control_assert(adev->c1_reset);
++	reset_control_assert(adev->c2_reset);
++
++	reset_control_deassert(adev->clk_reset);
++	reset_control_deassert(adev->c0_reset);
++	reset_control_deassert(adev->c1_reset);
++	reset_control_deassert(adev->c2_reset);
++
++	adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS,
++				sizeof(*adev->channels), GFP_KERNEL);
++
++	if (!adev->channels) {
++		ret = -ENOMEM;
++		goto err_disable_clks;
++	}
++
++	/* allocate and initialize channels */
++	INIT_LIST_HEAD(&adev->common.channels);
++
++	for (i = 0; i < ADM_MAX_CHANNELS; i++)
++		adm_channel_init(adev, &adev->channels[i], i);
++
++	/* reset CRCIs */
++	for (i = 0; i < 16; i++)
++		writel(ADM_CRCI_CTL_RST, adev->regs +
++			ADM_CRCI_CTL(i, adev->ee));
++
++	/* configure client interfaces */
++	writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) |
++		ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0));
++	writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) |
++		ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1));
++	writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) |
++		ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2));
++	writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf),
++		adev->regs + ADM_GP_CTL);
++
++	ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq,
++			0, "adm_dma", adev);
++	if (ret)
++		goto err_disable_clks;
++
++	platform_set_drvdata(pdev, adev);
++
++	adev->common.dev = adev->dev;
++	adev->common.dev->dma_parms = &adev->dma_parms;
++
++	/* set capabilities */
++	dma_cap_zero(adev->common.cap_mask);
++	dma_cap_set(DMA_SLAVE, adev->common.cap_mask);
++	dma_cap_set(DMA_PRIVATE, adev->common.cap_mask);
++
++	/* initialize dmaengine apis */
++	adev->common.directions = BIT(DMA_DEV_TO_MEM | DMA_MEM_TO_DEV);
++	adev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
++	adev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	adev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
++	adev->common.device_free_chan_resources = adm_free_chan;
++	adev->common.device_prep_slave_sg = adm_prep_slave_sg;
++	adev->common.device_issue_pending = adm_issue_pending;
++	adev->common.device_tx_status = adm_tx_status;
++	adev->common.device_terminate_all = adm_terminate_all;
++	adev->common.device_config = adm_slave_config;
++
++	ret = dma_async_device_register(&adev->common);
++	if (ret) {
++		dev_err(adev->dev, "failed to register dma async device\n");
++		goto err_disable_clks;
++	}
++
++	ret = of_dma_controller_register(pdev->dev.of_node,
++					 of_dma_xlate_by_chan_id,
++					 &adev->common);
++	if (ret)
++		goto err_unregister_dma;
++
++	return 0;
++
++err_unregister_dma:
++	dma_async_device_unregister(&adev->common);
++err_disable_clks:
++	clk_disable_unprepare(adev->iface_clk);
++err_disable_core_clk:
++	clk_disable_unprepare(adev->core_clk);
++
++	return ret;
++}
++
++static int adm_dma_remove(struct platform_device *pdev)
++{
++	struct adm_device *adev = platform_get_drvdata(pdev);
++	struct adm_chan *achan;
++	u32 i;
++
++	of_dma_controller_free(pdev->dev.of_node);
++	dma_async_device_unregister(&adev->common);
++
++	for (i = 0; i < ADM_MAX_CHANNELS; i++) {
++		achan = &adev->channels[i];
++
++		/* mask IRQs for this channel/EE pair */
++		writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
++
++		adm_terminate_all(&adev->channels[i].vc.chan);
++	}
++
++	devm_free_irq(adev->dev, adev->irq, adev);
++
++	clk_disable_unprepare(adev->core_clk);
++	clk_disable_unprepare(adev->iface_clk);
++
++	return 0;
++}
++
++static const struct of_device_id adm_of_match[] = {
++	{ .compatible = "qcom,adm", },
++	{}
++};
++MODULE_DEVICE_TABLE(of, adm_of_match);
++
++static struct platform_driver adm_dma_driver = {
++	.probe = adm_dma_probe,
++	.remove = adm_dma_remove,
++	.driver = {
++		.name = "adm-dma-engine",
++		.of_match_table = adm_of_match,
++	},
++};
++
++module_platform_driver(adm_dma_driver);
++
++MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
++MODULE_DESCRIPTION("QCOM ADM DMA engine driver");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ipq806x/patches-4.14/0030-clk-Disable-i2c-device-on-gsbi4.patch b/target/linux/ipq806x/patches-4.14/0030-clk-Disable-i2c-device-on-gsbi4.patch
new file mode 100644
index 0000000..52b60e1
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0030-clk-Disable-i2c-device-on-gsbi4.patch
@@ -0,0 +1,40 @@ 
+From 0c974b87829e007dc4fae94e20d488204e20e662 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 9 Mar 2017 08:16:10 +0100
+Subject: [PATCH 30/69] clk: Disable i2c device on gsbi4
+
+This patch was not annotated and comes from the v4.4 tree.
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/clk/qcom/gcc-ipq806x.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/clk/qcom/gcc-ipq806x.c
++++ b/drivers/clk/qcom/gcc-ipq806x.c
+@@ -294,7 +294,7 @@ static struct clk_rcg gsbi1_uart_src = {
+			.parent_names = gcc_pxo_pll8,
+			.num_parents = 2,
+			.ops = &clk_rcg_ops,
+-			.flags = CLK_SET_PARENT_GATE,
++			.flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED,
+		},
+	},
+ };
+@@ -312,7 +312,7 @@ static struct clk_branch gsbi1_uart_clk
+			},
+			.num_parents = 1,
+			.ops = &clk_branch_ops,
+-			.flags = CLK_SET_RATE_PARENT,
++			.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+		},
+	},
+ };
+@@ -890,6 +890,7 @@ static struct clk_branch gsbi1_h_clk = {
+		.hw.init = &(struct clk_init_data){
+			.name = "gsbi1_h_clk",
+			.ops = &clk_branch_ops,
++			.flags = CLK_IGNORE_UNUSED,
+		},
+	},
+ };
diff --git a/target/linux/ipq806x/patches-4.14/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch b/target/linux/ipq806x/patches-4.14/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch
new file mode 100644
index 0000000..a803269
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0031-mtd-add-SMEM-parser-for-QCOM-platforms.patch
@@ -0,0 +1,282 @@ 
+From d8eeb4de90e968ba32d956728c866f20752cf2c3 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu@codeaurora.org>
+Date: Thu, 9 Mar 2017 08:18:08 +0100
+Subject: [PATCH 31/69] mtd: add SMEM parser for QCOM platforms
+
+On QCOM platforms using MTD devices storage (such as IPQ806x), SMEM is
+used to store partition layout. This new parser can now be used to read
+SMEM and use it to register an MTD layout according to its content.
+
+Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org>
+---
+ drivers/mtd/Kconfig          |   7 ++
+ drivers/mtd/Makefile         |   1 +
+ drivers/mtd/qcom_smem_part.c | 228 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 236 insertions(+)
+ create mode 100644 drivers/mtd/qcom_smem_part.c
+
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -194,6 +194,13 @@ config MTD_MYLOADER_PARTS
+	  You will still need the parsing functions to be called by the driver
+	  for your particular device. It won't happen automatically.
+
++config MTD_QCOM_SMEM_PARTS
++	tristate "QCOM SMEM partitioning support"
++	depends on QCOM_SMEM
++	help
++	  This provides partitions parser for QCOM devices using SMEM
++	  such as IPQ806x.
++
+ comment "User Modules And Translation Layers"
+
+ #
+--- /dev/null
++++ b/drivers/mtd/qcom_smem_part.c
+@@ -0,0 +1,235 @@
++/*
++ * Copyright (c) 2015, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/slab.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/spi/spi.h>
++#include <linux/module.h>
++
++#include <linux/soc/qcom/smem.h>
++
++/* Processor/host identifier for the application processor */
++#define SMEM_HOST_APPS			0
++
++/* SMEM items index */
++#define SMEM_AARM_PARTITION_TABLE	9
++#define SMEM_BOOT_FLASH_TYPE		421
++#define SMEM_BOOT_FLASH_BLOCK_SIZE	424
++
++/* SMEM Flash types */
++#define SMEM_FLASH_NAND			2
++#define SMEM_FLASH_SPI			6
++
++#define SMEM_PART_NAME_SZ		16
++#define SMEM_PARTS_MAX			32
++
++struct smem_partition {
++	char name[SMEM_PART_NAME_SZ];
++	__le32 start;
++	__le32 size;
++	__le32 attr;
++};
++
++struct smem_partition_table {
++	u8 magic[8];
++	__le32 version;
++	__le32 len;
++	struct smem_partition parts[SMEM_PARTS_MAX];
++};
++
++/* SMEM Magic values in partition table */
++static const u8 SMEM_PTABLE_MAGIC[] = {
++	0xaa, 0x73, 0xee, 0x55,
++	0xdb, 0xbd, 0x5e, 0xe3,
++};
++
++static int qcom_smem_get_flash_blksz(u64 **smem_blksz)
++{
++	size_t size;
++
++	*smem_blksz = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_BLOCK_SIZE,
++			    	    &size);
++
++	if (IS_ERR(*smem_blksz)) {
++		pr_err("Unable to read flash blksz from SMEM\n");
++		return -ENOENT;
++	}
++
++	if (size != sizeof(**smem_blksz)) {
++		pr_err("Invalid flash blksz size in SMEM\n");
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int qcom_smem_get_flash_type(u64 **smem_flash_type)
++{
++	size_t size;
++
++	*smem_flash_type = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_TYPE,
++			    		&size);
++
++	if (IS_ERR(*smem_flash_type)) {
++		pr_err("Unable to read flash type from SMEM\n");
++		return -ENOENT;
++	}
++
++	if (size != sizeof(**smem_flash_type)) {
++		pr_err("Invalid flash type size in SMEM\n");
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int qcom_smem_get_flash_partitions(struct smem_partition_table **pparts)
++{
++	size_t size;
++
++	*pparts = qcom_smem_get(SMEM_HOST_APPS, SMEM_AARM_PARTITION_TABLE,
++				&size);
++
++	if (IS_ERR(*pparts)) {
++		pr_err("Unable to read partition table from SMEM\n");
++		return -ENOENT;
++	}
++
++	return 0;
++}
++
++static int of_dev_node_match(struct device *dev, void *data)
++{
++	return dev->of_node == data;
++}
++
++static bool is_spi_device(struct device_node *np)
++{
++	struct device *dev;
++
++	dev = bus_find_device(&spi_bus_type, NULL, np, of_dev_node_match);
++	if (!dev)
++		return false;
++
++	put_device(dev);
++	return true;
++}
++
++static int parse_qcom_smem_partitions(struct mtd_info *master,
++				      const struct mtd_partition **pparts,
++				      struct mtd_part_parser_data *data)
++{
++	struct smem_partition_table *smem_parts;
++	u64 *smem_flash_type, *smem_blksz;
++	struct mtd_partition *mtd_parts;
++	struct device_node *of_node = master->dev.of_node;
++	int i, ret;
++
++	/*
++	 * SMEM will only store the partition table of the boot device.
++	 * If this is not the boot device, do not return any partition.
++	 */
++	ret = qcom_smem_get_flash_type(&smem_flash_type);
++	if (ret < 0)
++		return ret;
++
++	if ((*smem_flash_type == SMEM_FLASH_NAND && !mtd_type_is_nand(master))
++	    || (*smem_flash_type == SMEM_FLASH_SPI && !is_spi_device(of_node)))
++		return 0;
++
++	/*
++	 * Just for sanity purpose, make sure the block size in SMEM matches the
++	 * block size of the MTD device
++	 */
++	ret = qcom_smem_get_flash_blksz(&smem_blksz);
++	if (ret < 0)
++		return ret;
++
++	if (*smem_blksz != master->erasesize) {
++		pr_err("SMEM block size differs from MTD block size\n");
++		return -EINVAL;
++	}
++
++	/* Get partition pointer from SMEM */
++	ret = qcom_smem_get_flash_partitions(&smem_parts);
++	if (ret < 0)
++		return ret;
++
++	if (memcmp(SMEM_PTABLE_MAGIC, smem_parts->magic,
++		   sizeof(SMEM_PTABLE_MAGIC))) {
++		pr_err("SMEM partition magic invalid\n");
++		return -EINVAL;
++	}
++
++	/* Allocate and populate the mtd structures */
++	mtd_parts = kcalloc(le32_to_cpu(smem_parts->len), sizeof(*mtd_parts),
++			    GFP_KERNEL);
++	if (!mtd_parts)
++		return -ENOMEM;
++
++	for (i = 0; i < smem_parts->len; i++) {
++		struct smem_partition *s_part = &smem_parts->parts[i];
++		struct mtd_partition *m_part = &mtd_parts[i];
++
++		m_part->name = s_part->name;
++		m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz);
++		m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz);
++
++		/*
++		 * The last SMEM partition may have its size marked as
++		 * something like 0xffffffff, which means "until the end of the
++		 * flash device". In this case, truncate it.
++		 */
++		if (m_part->offset + m_part->size > master->size)
++			m_part->size = master->size - m_part->offset;
++	}
++
++	*pparts = mtd_parts;
++
++	return smem_parts->len;
++}
++
++static const struct of_device_id qcom_smem_of_match_table[] = {
++	{ .compatible = "qcom,smem" },
++	{},
++};
++MODULE_DEVICE_TABLE(of, qcom_smem_of_match_table);
++
++static struct mtd_part_parser qcom_smem_parser = {
++	.owner = THIS_MODULE,
++	.parse_fn = parse_qcom_smem_partitions,
++	.name = "qcom-smem",
++	.of_match_table = qcom_smem_of_match_table,
++};
++
++static int __init qcom_smem_parser_init(void)
++{
++	register_mtd_parser(&qcom_smem_parser);
++	return 0;
++}
++
++static void __exit qcom_smem_parser_exit(void)
++{
++	deregister_mtd_parser(&qcom_smem_parser);
++}
++
++module_init(qcom_smem_parser_init);
++module_exit(qcom_smem_parser_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>");
++MODULE_DESCRIPTION("Parsing code for SMEM based partition tables");
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -17,6 +17,7 @@ obj-$(CONFIG_MTD_AR7_PARTS)	+= ar7part.o
+ obj-$(CONFIG_MTD_BCM63XX_PARTS)	+= bcm63xxpart.o
+ obj-$(CONFIG_MTD_BCM47XX_PARTS)	+= bcm47xxpart.o
+ obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
++obj-$(CONFIG_MTD_QCOM_SMEM_PARTS) += qcom_smem_part.o
+ obj-y				+= parsers/
+
+ # 'Users' - code which presents functionality to userspace.
diff --git a/target/linux/ipq806x/patches-4.14/0032-phy-add-qcom-dwc3-phy.patch b/target/linux/ipq806x/patches-4.14/0032-phy-add-qcom-dwc3-phy.patch
new file mode 100644
index 0000000..f392a71
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0032-phy-add-qcom-dwc3-phy.patch
@@ -0,0 +1,616 @@ 
+From b9004f4fd23e4c614d71c972f3a9311665480e29 Mon Sep 17 00:00:00 2001
+From: Andy Gross <agross@codeaurora.org>
+Date: Thu, 9 Mar 2017 08:19:18 +0100
+Subject: [PATCH 32/69] phy: add qcom dwc3 phy
+
+Signed-off-by: Andy Gross <agross@codeaurora.org>
+---
+ drivers/phy/Kconfig         |  12 +
+ drivers/phy/Makefile        |   1 +
+ drivers/phy/phy-qcom-dwc3.c | 575 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 588 insertions(+)
+ create mode 100644 drivers/phy/phy-qcom-dwc3.c
+
+--- a/drivers/phy/qualcomm/Kconfig
++++ b/drivers/phy/qualcomm/Kconfig
+@@ -56,3 +56,15 @@
+	select GENERIC_PHY
+	help
+	  Support for the USB HSIC ULPI compliant PHY on QCOM chipsets.
++
++config PHY_QCOM_DWC3
++	tristate "QCOM DWC3 USB PHY support"
++	depends on ARCH_QCOM
++	depends on HAS_IOMEM
++	depends on OF
++	select GENERIC_PHY
++	help
++	  This option enables support for the Synopsis PHYs present inside the
++	  Qualcomm USB3.0 DWC3 controller.  This driver supports both HS and SS
++	  PHY controllers.
++
+--- a/drivers/phy/qualcomm/Makefile
++++ b/drivers/phy/qualcomm/Makefile
+@@ -8,3 +8,4 @@
+ obj-$(CONFIG_PHY_QCOM_UFS)		+= phy-qcom-ufs-qmp-20nm.o
+ obj-$(CONFIG_PHY_QCOM_USB_HS) 		+= phy-qcom-usb-hs.o
+ obj-$(CONFIG_PHY_QCOM_USB_HSIC) 	+= phy-qcom-usb-hsic.o
++obj-$(CONFIG_PHY_QCOM_DWC3)		+= phy-qcom-dwc3.o
+--- /dev/null
++++ b/drivers/phy/qualcomm/phy-qcom-dwc3.c
+@@ -0,0 +1,575 @@
++/* Copyright (c) 2014-2015, Code Aurora Forum. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++* This program is distributed in the hope that it will be useful,
++* but WITHOUT ANY WARRANTY; without even the implied warranty of
++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++* GNU General Public License for more details.
++*/
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++
++/**
++ *  USB QSCRATCH Hardware registers
++ */
++#define QSCRATCH_GENERAL_CFG		(0x08)
++#define HSUSB_PHY_CTRL_REG		(0x10)
++
++/* PHY_CTRL_REG */
++#define HSUSB_CTRL_DMSEHV_CLAMP			BIT(24)
++#define HSUSB_CTRL_USB2_SUSPEND			BIT(23)
++#define HSUSB_CTRL_UTMI_CLK_EN			BIT(21)
++#define HSUSB_CTRL_UTMI_OTG_VBUS_VALID		BIT(20)
++#define HSUSB_CTRL_USE_CLKCORE			BIT(18)
++#define HSUSB_CTRL_DPSEHV_CLAMP			BIT(17)
++#define HSUSB_CTRL_COMMONONN			BIT(11)
++#define HSUSB_CTRL_ID_HV_CLAMP			BIT(9)
++#define HSUSB_CTRL_OTGSESSVLD_CLAMP		BIT(8)
++#define HSUSB_CTRL_CLAMP_EN			BIT(7)
++#define HSUSB_CTRL_RETENABLEN			BIT(1)
++#define HSUSB_CTRL_POR				BIT(0)
++
++/* QSCRATCH_GENERAL_CFG */
++#define HSUSB_GCFG_XHCI_REV		BIT(2)
++
++/**
++ *  USB QSCRATCH Hardware registers
++ */
++#define SSUSB_PHY_CTRL_REG		(0x00)
++#define SSUSB_PHY_PARAM_CTRL_1		(0x04)
++#define SSUSB_PHY_PARAM_CTRL_2		(0x08)
++#define CR_PROTOCOL_DATA_IN_REG		(0x0c)
++#define CR_PROTOCOL_DATA_OUT_REG	(0x10)
++#define CR_PROTOCOL_CAP_ADDR_REG	(0x14)
++#define CR_PROTOCOL_CAP_DATA_REG	(0x18)
++#define CR_PROTOCOL_READ_REG		(0x1c)
++#define CR_PROTOCOL_WRITE_REG		(0x20)
++
++/* PHY_CTRL_REG */
++#define SSUSB_CTRL_REF_USE_PAD		BIT(28)
++#define SSUSB_CTRL_TEST_POWERDOWN	BIT(27)
++#define SSUSB_CTRL_LANE0_PWR_PRESENT	BIT(24)
++#define SSUSB_CTRL_SS_PHY_EN		BIT(8)
++#define SSUSB_CTRL_SS_PHY_RESET		BIT(7)
++
++/* SSPHY control registers */
++#define SSPHY_CTRL_RX_OVRD_IN_HI(lane)	(0x1006 + 0x100 * lane)
++#define SSPHY_CTRL_TX_OVRD_DRV_LO(lane)	(0x1002 + 0x100 * lane)
++
++/* SSPHY SoC version specific values */
++#define SSPHY_RX_EQ_VALUE		4	/* Override value for rx_eq */
++#define SSPHY_TX_DEEMPH_3_5DB		23	/* Override value for transmit
++						   preemphasis */
++#define SSPHY_MPLL_VALUE		0	/* Override value for mpll */
++
++/* QSCRATCH PHY_PARAM_CTRL1 fields */
++#define PHY_PARAM_CTRL1_TX_FULL_SWING_MASK	0x07f00000u
++#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK	0x000fc000u
++#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK	0x00003f00u
++#define PHY_PARAM_CTRL1_LOS_BIAS_MASK		0x000000f8u
++
++#define PHY_PARAM_CTRL1_MASK				\
++		(PHY_PARAM_CTRL1_TX_FULL_SWING_MASK |	\
++		 PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK |	\
++		 PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK |	\
++		 PHY_PARAM_CTRL1_LOS_BIAS_MASK)
++
++#define PHY_PARAM_CTRL1_TX_FULL_SWING(x)	\
++		(((x) << 20) & PHY_PARAM_CTRL1_TX_FULL_SWING_MASK)
++#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB(x)	\
++		(((x) << 14) & PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK)
++#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(x)	\
++		(((x) <<  8) & PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK)
++#define PHY_PARAM_CTRL1_LOS_BIAS(x)	\
++		(((x) <<  3) & PHY_PARAM_CTRL1_LOS_BIAS_MASK)
++
++/* RX OVRD IN HI bits */
++#define RX_OVRD_IN_HI_RX_RESET_OVRD		BIT(13)
++#define RX_OVRD_IN_HI_RX_RX_RESET		BIT(12)
++#define RX_OVRD_IN_HI_RX_EQ_OVRD		BIT(11)
++#define RX_OVRD_IN_HI_RX_EQ_MASK		0x0700
++#define RX_OVRD_IN_HI_RX_EQ_SHIFT		8
++#define RX_OVRD_IN_HI_RX_EQ_EN_OVRD		BIT(7)
++#define RX_OVRD_IN_HI_RX_EQ_EN			BIT(6)
++#define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD	BIT(5)
++#define RX_OVRD_IN_HI_RX_LOS_FILTER_MASK	0x0018
++#define RX_OVRD_IN_HI_RX_RATE_OVRD		BIT(2)
++#define RX_OVRD_IN_HI_RX_RATE_MASK		0x0003
++
++/* TX OVRD DRV LO register bits */
++#define TX_OVRD_DRV_LO_AMPLITUDE_MASK	0x007F
++#define TX_OVRD_DRV_LO_PREEMPH_MASK	0x3F80
++#define TX_OVRD_DRV_LO_PREEMPH_SHIFT	7
++#define TX_OVRD_DRV_LO_EN		BIT(14)
++
++/* SS CAP register bits */
++#define SS_CR_CAP_ADDR_REG		BIT(0)
++#define SS_CR_CAP_DATA_REG		BIT(0)
++#define SS_CR_READ_REG			BIT(0)
++#define SS_CR_WRITE_REG			BIT(0)
++
++struct qcom_dwc3_usb_phy {
++	void __iomem		*base;
++	struct device		*dev;
++	struct clk		*xo_clk;
++	struct clk		*ref_clk;
++	u32			rx_eq;
++	u32			tx_deamp_3_5db;
++	u32			mpll;
++};
++
++struct qcom_dwc3_phy_drvdata {
++	struct phy_ops	ops;
++	u32		clk_rate;
++};
++
++/**
++ * Write register and read back masked value to confirm it is written
++ *
++ * @base - QCOM DWC3 PHY base virtual address.
++ * @offset - register offset.
++ * @mask - register bitmask specifying what should be updated
++ * @val - value to write.
++ */
++static inline void qcom_dwc3_phy_write_readback(
++	struct qcom_dwc3_usb_phy *phy_dwc3, u32 offset,
++	const u32 mask, u32 val)
++{
++	u32 write_val, tmp = readl(phy_dwc3->base + offset);
++
++	tmp &= ~mask;		/* retain other bits */
++	write_val = tmp | val;
++
++	writel(write_val, phy_dwc3->base + offset);
++
++	/* Read back to see if val was written */
++	tmp = readl(phy_dwc3->base + offset);
++	tmp &= mask;		/* clear other bits */
++
++	if (tmp != val)
++		dev_err(phy_dwc3->dev, "write: %x to QSCRATCH: %x FAILED\n",
++			val, offset);
++}
++
++static int wait_for_latch(void __iomem *addr)
++{
++	u32 retry = 10;
++
++	while (true) {
++		if (!readl(addr))
++			break;
++
++		if (--retry == 0)
++			return -ETIMEDOUT;
++
++		usleep_range(10, 20);
++	}
++
++	return 0;
++}
++
++/**
++ * Write SSPHY register
++ *
++ * @base - QCOM DWC3 PHY base virtual address.
++ * @addr - SSPHY address to write.
++ * @val - value to write.
++ */
++static int qcom_dwc3_ss_write_phycreg(struct qcom_dwc3_usb_phy *phy_dwc3,
++					u32 addr, u32 val)
++{
++	int ret;
++
++	writel(addr, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
++	writel(SS_CR_CAP_ADDR_REG, phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
++
++	ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_ADDR_REG);
++	if (ret)
++		goto err_wait;
++
++	writel(val, phy_dwc3->base + CR_PROTOCOL_DATA_IN_REG);
++	writel(SS_CR_CAP_DATA_REG, phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
++
++	ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_CAP_DATA_REG);
++	if (ret)
++		goto err_wait;
++
++	writel(SS_CR_WRITE_REG, phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
++
++	ret = wait_for_latch(phy_dwc3->base + CR_PROTOCOL_WRITE_REG);
++
++err_wait:
++	if (ret)
++		dev_err(phy_dwc3->dev, "timeout waiting for latch\n");
++	return ret;
++}
++
++/**
++ * Read SSPHY register.
++ *
++ * @base - QCOM DWC3 PHY base virtual address.
++ * @addr - SSPHY address to read.
++ */
++static int qcom_dwc3_ss_read_phycreg(void __iomem *base, u32 addr, u32 *val)
++{
++	int ret;
++
++	writel(addr, base + CR_PROTOCOL_DATA_IN_REG);
++	writel(SS_CR_CAP_ADDR_REG, base + CR_PROTOCOL_CAP_ADDR_REG);
++
++	ret = wait_for_latch(base + CR_PROTOCOL_CAP_ADDR_REG);
++	if (ret)
++		goto err_wait;
++
++	/*
++	 * Due to hardware bug, first read of SSPHY register might be
++	 * incorrect. Hence as workaround, SW should perform SSPHY register
++	 * read twice, but use only second read and ignore first read.
++	 */
++	writel(SS_CR_READ_REG, base + CR_PROTOCOL_READ_REG);
++
++	ret = wait_for_latch(base + CR_PROTOCOL_READ_REG);
++	if (ret)
++		goto err_wait;
++
++	/* throwaway read */
++	readl(base + CR_PROTOCOL_DATA_OUT_REG);
++
++	writel(SS_CR_READ_REG, base + CR_PROTOCOL_READ_REG);
++
++	ret = wait_for_latch(base + CR_PROTOCOL_READ_REG);
++	if (ret)
++		goto err_wait;
++
++	*val = readl(base + CR_PROTOCOL_DATA_OUT_REG);
++
++err_wait:
++	return ret;
++}
++
++static int qcom_dwc3_hs_phy_init(struct phy *phy)
++{
++	struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
++	int ret;
++	u32 val;
++
++	ret = clk_prepare_enable(phy_dwc3->xo_clk);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(phy_dwc3->ref_clk);
++	if (ret) {
++		clk_disable_unprepare(phy_dwc3->xo_clk);
++		return ret;
++	}
++
++	/*
++	 * HSPHY Initialization: Enable UTMI clock, select 19.2MHz fsel
++	 * enable clamping, and disable RETENTION (power-on default is ENABLED)
++	 */
++	val = HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_DMSEHV_CLAMP |
++		HSUSB_CTRL_RETENABLEN  | HSUSB_CTRL_COMMONONN |
++		HSUSB_CTRL_OTGSESSVLD_CLAMP | HSUSB_CTRL_ID_HV_CLAMP |
++		HSUSB_CTRL_DPSEHV_CLAMP | HSUSB_CTRL_UTMI_OTG_VBUS_VALID |
++		HSUSB_CTRL_UTMI_CLK_EN | HSUSB_CTRL_CLAMP_EN | 0x70;
++
++	/* use core clock if external reference is not present */
++	if (!phy_dwc3->xo_clk)
++		val |= HSUSB_CTRL_USE_CLKCORE;
++
++	writel(val, phy_dwc3->base + HSUSB_PHY_CTRL_REG);
++	usleep_range(2000, 2200);
++
++	/* Disable (bypass) VBUS and ID filters */
++	writel(HSUSB_GCFG_XHCI_REV, phy_dwc3->base + QSCRATCH_GENERAL_CFG);
++
++	return 0;
++}
++
++static int qcom_dwc3_hs_phy_exit(struct phy *phy)
++{
++	struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
++
++	clk_disable_unprepare(phy_dwc3->ref_clk);
++	clk_disable_unprepare(phy_dwc3->xo_clk);
++
++	return 0;
++}
++
++static int qcom_dwc3_ss_phy_init(struct phy *phy)
++{
++	struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
++	int ret;
++	u32 data = 0;
++
++	ret = clk_prepare_enable(phy_dwc3->xo_clk);
++	if (ret)
++		return ret;
++
++	ret = clk_prepare_enable(phy_dwc3->ref_clk);
++	if (ret) {
++		clk_disable_unprepare(phy_dwc3->xo_clk);
++		return ret;
++	}
++
++	/* reset phy */
++	data = readl(phy_dwc3->base + SSUSB_PHY_CTRL_REG);
++	writel(data | SSUSB_CTRL_SS_PHY_RESET,
++		phy_dwc3->base + SSUSB_PHY_CTRL_REG);
++	usleep_range(2000, 2200);
++	writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
++
++	/* clear REF_PAD if we don't have XO clk */
++	if (!phy_dwc3->xo_clk)
++		data &= ~SSUSB_CTRL_REF_USE_PAD;
++	else
++		data |= SSUSB_CTRL_REF_USE_PAD;
++
++	writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
++
++	/* wait for ref clk to become stable, this can take up to 30ms */
++	msleep(30);
++
++	data |= SSUSB_CTRL_SS_PHY_EN | SSUSB_CTRL_LANE0_PWR_PRESENT;
++	writel(data, phy_dwc3->base + SSUSB_PHY_CTRL_REG);
++
++	/*
++	 * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
++	 * in HS mode instead of SS mode. Workaround it by asserting
++	 * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
++	 */
++	ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base, 0x102D, &data);
++	if (ret)
++		goto err_phy_trans;
++
++	data |= (1 << 7);
++	ret = qcom_dwc3_ss_write_phycreg(phy_dwc3, 0x102D, data);
++	if (ret)
++		goto err_phy_trans;
++
++	ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base, 0x1010, &data);
++	if (ret)
++		goto err_phy_trans;
++
++	data &= ~0xff0;
++	data |= 0x20;
++	ret = qcom_dwc3_ss_write_phycreg(phy_dwc3, 0x1010, data);
++	if (ret)
++		goto err_phy_trans;
++
++	/*
++	 * Fix RX Equalization setting as follows
++	 * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
++	 * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
++	 * LANE0.RX_OVRD_IN_HI.RX_EQ set based on SoC version
++	 * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
++	 */
++	ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base,
++			SSPHY_CTRL_RX_OVRD_IN_HI(0), &data);
++	if (ret)
++		goto err_phy_trans;
++
++	data &= ~RX_OVRD_IN_HI_RX_EQ_EN;
++	data |= RX_OVRD_IN_HI_RX_EQ_EN_OVRD;
++	data &= ~RX_OVRD_IN_HI_RX_EQ_MASK;
++	data |= phy_dwc3->rx_eq << RX_OVRD_IN_HI_RX_EQ_SHIFT;
++	data |= RX_OVRD_IN_HI_RX_EQ_OVRD;
++	ret = qcom_dwc3_ss_write_phycreg(phy_dwc3,
++		SSPHY_CTRL_RX_OVRD_IN_HI(0), data);
++	if (ret)
++		goto err_phy_trans;
++
++	/*
++	 * Set EQ and TX launch amplitudes as follows
++	 * LANE0.TX_OVRD_DRV_LO.PREEMPH set based on SoC version
++	 * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 110
++	 * LANE0.TX_OVRD_DRV_LO.EN set to 1.
++	 */
++	ret = qcom_dwc3_ss_read_phycreg(phy_dwc3->base,
++		SSPHY_CTRL_TX_OVRD_DRV_LO(0), &data);
++	if (ret)
++		goto err_phy_trans;
++
++	data &= ~TX_OVRD_DRV_LO_PREEMPH_MASK;
++	data |= phy_dwc3->tx_deamp_3_5db << TX_OVRD_DRV_LO_PREEMPH_SHIFT;
++	data &= ~TX_OVRD_DRV_LO_AMPLITUDE_MASK;
++	data |= 0x6E;
++	data |= TX_OVRD_DRV_LO_EN;
++	ret = qcom_dwc3_ss_write_phycreg(phy_dwc3,
++		SSPHY_CTRL_TX_OVRD_DRV_LO(0), data);
++	if (ret)
++		goto err_phy_trans;
++
++	qcom_dwc3_ss_write_phycreg(phy_dwc3, 0x30, phy_dwc3->mpll);
++
++	/*
++	 * Set the QSCRATCH PHY_PARAM_CTRL1 parameters as follows
++	 * TX_FULL_SWING [26:20] amplitude to 110
++	 * TX_DEEMPH_6DB [19:14] to 32
++	 * TX_DEEMPH_3_5DB [13:8] set based on SoC version
++	 * LOS_BIAS [7:3] to 9
++	 */
++	data = readl(phy_dwc3->base + SSUSB_PHY_PARAM_CTRL_1);
++
++	data &= ~PHY_PARAM_CTRL1_MASK;
++
++	data |= PHY_PARAM_CTRL1_TX_FULL_SWING(0x6e) |
++		PHY_PARAM_CTRL1_TX_DEEMPH_6DB(0x20) |
++		PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(phy_dwc3->tx_deamp_3_5db) |
++		PHY_PARAM_CTRL1_LOS_BIAS(0x9);
++
++	qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_PARAM_CTRL_1,
++				     PHY_PARAM_CTRL1_MASK, data);
++
++err_phy_trans:
++	return ret;
++}
++
++static int qcom_dwc3_ss_phy_exit(struct phy *phy)
++{
++	struct qcom_dwc3_usb_phy *phy_dwc3 = phy_get_drvdata(phy);
++
++	/* Sequence to put SSPHY in low power state:
++	 * 1. Clear REF_PHY_EN in PHY_CTRL_REG
++	 * 2. Clear REF_USE_PAD in PHY_CTRL_REG
++	 * 3. Set TEST_POWERED_DOWN in PHY_CTRL_REG to enable PHY retention
++	 */
++	qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
++		SSUSB_CTRL_SS_PHY_EN, 0x0);
++	qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
++		SSUSB_CTRL_REF_USE_PAD, 0x0);
++	qcom_dwc3_phy_write_readback(phy_dwc3, SSUSB_PHY_CTRL_REG,
++		SSUSB_CTRL_TEST_POWERDOWN, 0x0);
++
++	clk_disable_unprepare(phy_dwc3->ref_clk);
++	clk_disable_unprepare(phy_dwc3->xo_clk);
++
++	return 0;
++}
++
++static const struct qcom_dwc3_phy_drvdata qcom_dwc3_hs_drvdata = {
++	.ops = {
++		.init		= qcom_dwc3_hs_phy_init,
++		.exit		= qcom_dwc3_hs_phy_exit,
++		.owner		= THIS_MODULE,
++	},
++	.clk_rate = 60000000,
++};
++
++static const struct qcom_dwc3_phy_drvdata qcom_dwc3_ss_drvdata = {
++	.ops = {
++		.init		= qcom_dwc3_ss_phy_init,
++		.exit		= qcom_dwc3_ss_phy_exit,
++		.owner		= THIS_MODULE,
++	},
++	.clk_rate = 125000000,
++};
++
++static const struct of_device_id qcom_dwc3_phy_table[] = {
++	{ .compatible = "qcom,dwc3-hs-usb-phy", .data = &qcom_dwc3_hs_drvdata },
++	{ .compatible = "qcom,dwc3-ss-usb-phy", .data = &qcom_dwc3_ss_drvdata },
++	{ /* Sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, qcom_dwc3_phy_table);
++
++static int qcom_dwc3_phy_probe(struct platform_device *pdev)
++{
++	struct qcom_dwc3_usb_phy	*phy_dwc3;
++	struct phy_provider		*phy_provider;
++	struct phy			*generic_phy;
++	struct resource			*res;
++	const struct of_device_id *match;
++	const struct qcom_dwc3_phy_drvdata *data;
++	struct device_node *np;
++
++	phy_dwc3 = devm_kzalloc(&pdev->dev, sizeof(*phy_dwc3), GFP_KERNEL);
++	if (!phy_dwc3)
++		return -ENOMEM;
++
++	match = of_match_node(qcom_dwc3_phy_table, pdev->dev.of_node);
++	data = match->data;
++
++	phy_dwc3->dev = &pdev->dev;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	phy_dwc3->base = devm_ioremap_resource(phy_dwc3->dev, res);
++	if (IS_ERR(phy_dwc3->base))
++		return PTR_ERR(phy_dwc3->base);
++
++	phy_dwc3->ref_clk = devm_clk_get(phy_dwc3->dev, "ref");
++	if (IS_ERR(phy_dwc3->ref_clk)) {
++		dev_dbg(phy_dwc3->dev, "cannot get reference clock\n");
++		return PTR_ERR(phy_dwc3->ref_clk);
++	}
++
++	clk_set_rate(phy_dwc3->ref_clk, data->clk_rate);
++
++	phy_dwc3->xo_clk = devm_clk_get(phy_dwc3->dev, "xo");
++	if (IS_ERR(phy_dwc3->xo_clk)) {
++		dev_dbg(phy_dwc3->dev, "cannot get TCXO clock\n");
++		phy_dwc3->xo_clk = NULL;
++	}
++
++	/* Parse device node to probe HSIO settings */
++	np = of_node_get(pdev->dev.of_node);
++	if (!of_compat_cmp(match->compatible, "qcom,dwc3-ss-usb-phy",
++			   strlen(match->compatible))) {
++
++		if (of_property_read_u32(np, "rx_eq", &phy_dwc3->rx_eq) ||
++		    of_property_read_u32(np, "tx_deamp_3_5db",
++					 &phy_dwc3->tx_deamp_3_5db) ||
++		    of_property_read_u32(np, "mpll", &phy_dwc3->mpll)) {
++
++			dev_err(phy_dwc3->dev, "cannot get HSIO settings from device node, using default values\n");
++
++			/* Default HSIO settings */
++			phy_dwc3->rx_eq = SSPHY_RX_EQ_VALUE;
++			phy_dwc3->tx_deamp_3_5db = SSPHY_TX_DEEMPH_3_5DB;
++			phy_dwc3->mpll = SSPHY_MPLL_VALUE;
++		}
++	}
++
++	generic_phy = devm_phy_create(phy_dwc3->dev, pdev->dev.of_node,
++				      &data->ops);
++
++	if (IS_ERR(generic_phy))
++		return PTR_ERR(generic_phy);
++
++	phy_set_drvdata(generic_phy, phy_dwc3);
++	platform_set_drvdata(pdev, phy_dwc3);
++
++	phy_provider = devm_of_phy_provider_register(phy_dwc3->dev,
++			of_phy_simple_xlate);
++
++	if (IS_ERR(phy_provider))
++		return PTR_ERR(phy_provider);
++
++	return 0;
++}
++
++static struct platform_driver qcom_dwc3_phy_driver = {
++	.probe		= qcom_dwc3_phy_probe,
++	.driver		= {
++		.name	= "qcom-dwc3-usb-phy",
++		.owner	= THIS_MODULE,
++		.of_match_table = qcom_dwc3_phy_table,
++	},
++};
++
++module_platform_driver(qcom_dwc3_phy_driver);
++
++MODULE_ALIAS("platform:phy-qcom-dwc3");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
++MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
++MODULE_DESCRIPTION("DesignWare USB3 QCOM PHY driver");
diff --git a/target/linux/ipq806x/patches-4.14/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch b/target/linux/ipq806x/patches-4.14/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch
new file mode 100644
index 0000000..1948152
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0033-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch
@@ -0,0 +1,28 @@ 
+From 48051ece78136e4235a2415a52797db56f8a4478 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu@codeaurora.org>
+Date: Tue, 21 Apr 2015 19:09:07 -0700
+Subject: [PATCH 33/69] ARM: qcom: automatically select PCI_DOMAINS if PCI is
+ enabled
+
+If multiple PCIe devices are present in the system, the kernel will
+panic at boot time when trying to scan the PCI buses. This happens on
+IPQ806x based platforms, which has 3 PCIe ports.
+
+Enabling this option allows the kernel to assign the pci-domains
+according to the device-tree content. This allows multiple PCIe
+controllers to coexist in the system.
+
+Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+---
+ arch/arm/mach-qcom/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/mach-qcom/Kconfig
++++ b/arch/arm/mach-qcom/Kconfig
+@@ -6,6 +6,7 @@ menuconfig ARCH_QCOM
+	select ARM_AMBA
+	select PINCTRL
+	select QCOM_SCM if SMP
++	select PCI_DOMAINS if PCI
+	help
+	  Support for Qualcomm's devicetree based systems.
diff --git a/target/linux/ipq806x/patches-4.14/0034-ARM-Add-Krait-L2-register-accessor-functions.patch b/target/linux/ipq806x/patches-4.14/0034-ARM-Add-Krait-L2-register-accessor-functions.patch
new file mode 100644
index 0000000..3f820fa
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0034-ARM-Add-Krait-L2-register-accessor-functions.patch
@@ -0,0 +1,147 @@ 
+From patchwork Fri Dec  8 09:42:19 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,01/12] ARM: Add Krait L2 register accessor functions
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102101
+Message-Id: <1512726150-7204-2-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org, Mark Rutland <mark.rutland@arm.com>,
+ Russell King <linux@arm.linux.org.uk>,
+ Courtney Cavin <courtney.cavin@sonymobile.com>
+Date: Fri,  8 Dec 2017 15:12:19 +0530
+
+From: Stephen Boyd <sboyd@codeaurora.org>
+
+Krait CPUs have a handful of L2 cache controller registers that
+live behind a cp15 based indirection register. First you program
+the indirection register (l2cpselr) to point the L2 'window'
+register (l2cpdr) at what you want to read/write.  Then you
+read/write the 'window' register to do what you want. The
+l2cpselr register is not banked per-cpu so we must lock around
+accesses to it to prevent other CPUs from re-pointing l2cpdr
+underneath us.
+
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Russell King <linux@arm.linux.org.uk>
+Cc: Courtney Cavin <courtney.cavin@sonymobile.com>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ arch/arm/common/Kconfig                   |  3 ++
+ arch/arm/common/Makefile                  |  1 +
+ arch/arm/common/krait-l2-accessors.c      | 58 +++++++++++++++++++++++++++++++
+ arch/arm/include/asm/krait-l2-accessors.h | 20 +++++++++++
+ 4 files changed, 82 insertions(+)
+ create mode 100644 arch/arm/common/krait-l2-accessors.c
+ create mode 100644 arch/arm/include/asm/krait-l2-accessors.h
+
+--- a/arch/arm/common/Kconfig
++++ b/arch/arm/common/Kconfig
+@@ -7,6 +7,9 @@ config DMABOUNCE
+	bool
+	select ZONE_DMA
+
++config KRAIT_L2_ACCESSORS
++	bool
++
+ config SHARP_LOCOMO
+	bool
+
+--- a/arch/arm/common/Makefile
++++ b/arch/arm/common/Makefile
+@@ -7,6 +7,7 @@ obj-y				+= firmware.o
+
+ obj-$(CONFIG_SA1111)		+= sa1111.o
+ obj-$(CONFIG_DMABOUNCE)		+= dmabounce.o
++obj-$(CONFIG_KRAIT_L2_ACCESSORS) += krait-l2-accessors.o
+ obj-$(CONFIG_SHARP_LOCOMO)	+= locomo.o
+ obj-$(CONFIG_SHARP_PARAM)	+= sharpsl_param.o
+ obj-$(CONFIG_SHARP_SCOOP)	+= scoop.o
+--- /dev/null
++++ b/arch/arm/common/krait-l2-accessors.c
+@@ -0,0 +1,58 @@
++/*
++ * Copyright (c) 2011-2013, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/spinlock.h>
++#include <linux/export.h>
++
++#include <asm/barrier.h>
++#include <asm/krait-l2-accessors.h>
++
++static DEFINE_RAW_SPINLOCK(krait_l2_lock);
++
++void krait_set_l2_indirect_reg(u32 addr, u32 val)
++{
++	unsigned long flags;
++
++	raw_spin_lock_irqsave(&krait_l2_lock, flags);
++	/*
++	 * Select the L2 window by poking l2cpselr, then write to the window
++	 * via l2cpdr.
++	 */
++	asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
++	isb();
++	asm volatile ("mcr p15, 3, %0, c15, c0, 7 @ l2cpdr" : : "r" (val));
++	isb();
++
++	raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
++}
++EXPORT_SYMBOL(krait_set_l2_indirect_reg);
++
++u32 krait_get_l2_indirect_reg(u32 addr)
++{
++	u32 val;
++	unsigned long flags;
++
++	raw_spin_lock_irqsave(&krait_l2_lock, flags);
++	/*
++	 * Select the L2 window by poking l2cpselr, then read from the window
++	 * via l2cpdr.
++	 */
++	asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
++	isb();
++	asm volatile ("mrc p15, 3, %0, c15, c0, 7 @ l2cpdr" : "=r" (val));
++
++	raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
++
++	return val;
++}
++EXPORT_SYMBOL(krait_get_l2_indirect_reg);
+--- /dev/null
++++ b/arch/arm/include/asm/krait-l2-accessors.h
+@@ -0,0 +1,20 @@
++/*
++ * Copyright (c) 2011-2013, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __ASMARM_KRAIT_L2_ACCESSORS_H
++#define __ASMARM_KRAIT_L2_ACCESSORS_H
++
++extern void krait_set_l2_indirect_reg(u32 addr, u32 val);
++extern u32 krait_get_l2_indirect_reg(u32 addr);
++
++#endif
diff --git a/target/linux/ipq806x/patches-4.14/0035-clk-mux-Split-out-register-accessors-for-reuse.patch b/target/linux/ipq806x/patches-4.14/0035-clk-mux-Split-out-register-accessors-for-reuse.patch
new file mode 100644
index 0000000..43b25a3
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0035-clk-mux-Split-out-register-accessors-for-reuse.patch
@@ -0,0 +1,195 @@ 
+From patchwork Fri Dec  8 09:42:20 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,02/12] clk: mux: Split out register accessors for reuse
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102103
+Message-Id: <1512726150-7204-3-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:20 +0530
+
+From: Stephen Boyd <sboyd@codeaurora.org>
+
+We want to reuse the logic in clk-mux.c for other clock drivers
+that don't use readl as register accessors. Fortunately, there
+really isn't much to the mux code besides the table indirection
+and quirk flags if you assume any bit shifting and masking has
+been done already. Pull that logic out into reusable functions
+that operate on an optional table and some flags so that other
+drivers can use the same logic.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/clk-mux.c        | 75 +++++++++++++++++++++++++++-----------------
+ include/linux/clk-provider.h |  9 ++++--
+ 2 files changed, 54 insertions(+), 30 deletions(-)
+
+--- a/drivers/clk/clk-mux.c
++++ b/drivers/clk/clk-mux.c
+@@ -26,35 +26,24 @@
+  * parent - parent is adjustable through clk_set_parent
+  */
+
+-static u8 clk_mux_get_parent(struct clk_hw *hw)
++unsigned int clk_mux_get_parent(struct clk_hw *hw, unsigned int val,
++				unsigned int *table, unsigned long flags)
+ {
+-	struct clk_mux *mux = to_clk_mux(hw);
+	int num_parents = clk_hw_get_num_parents(hw);
+-	u32 val;
+-
+-	/*
+-	 * FIXME need a mux-specific flag to determine if val is bitwise or numeric
+-	 * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
+-	 * to 0x7 (index starts at one)
+-	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
+-	 * val = 0x4 really means "bit 2, index starts at bit 0"
+-	 */
+-	val = clk_readl(mux->reg) >> mux->shift;
+-	val &= mux->mask;
+
+-	if (mux->table) {
++	if (table) {
+		int i;
+
+		for (i = 0; i < num_parents; i++)
+-			if (mux->table[i] == val)
++			if (table[i] == val)
+				return i;
+		return -EINVAL;
+	}
+
+-	if (val && (mux->flags & CLK_MUX_INDEX_BIT))
++	if (val && (flags & CLK_MUX_INDEX_BIT))
+		val = ffs(val) - 1;
+
+-	if (val && (mux->flags & CLK_MUX_INDEX_ONE))
++	if (val && (flags & CLK_MUX_INDEX_ONE))
+		val--;
+
+	if (val >= num_parents)
+@@ -62,23 +51,53 @@ static u8 clk_mux_get_parent(struct clk_
+
+	return val;
+ }
++EXPORT_SYMBOL_GPL(clk_mux_get_parent);
+
+-static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
++static u8 _clk_mux_get_parent(struct clk_hw *hw)
+ {
+	struct clk_mux *mux = to_clk_mux(hw);
+	u32 val;
+-	unsigned long flags = 0;
+
+-	if (mux->table) {
+-		index = mux->table[index];
++	/*
++	 * FIXME need a mux-specific flag to determine if val is bitwise or
++	 * numeric e.g. sys_clkin_ck's clksel field is 3 bits wide,
++	 * but ranges from 0x1 to 0x7 (index starts at one)
++	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
++	 * val = 0x4 really means "bit 2, index starts at bit 0"
++	 */
++	val = clk_readl(mux->reg) >> mux->shift;
++	val &= mux->mask;
++
++	return clk_mux_get_parent(hw, val, mux->table, mux->flags);
++}
++
++unsigned int clk_mux_reindex(u8 index, unsigned int *table,
++			     unsigned long flags)
++{
++	unsigned int val = index;
++
++	if (table) {
++		val = table[val];
+	} else {
+-		if (mux->flags & CLK_MUX_INDEX_BIT)
+-			index = 1 << index;
++		if (flags & CLK_MUX_INDEX_BIT)
++			val = 1 << index;
+
+-		if (mux->flags & CLK_MUX_INDEX_ONE)
+-			index++;
++		if (flags & CLK_MUX_INDEX_ONE)
++			val++;
+	}
+
++	return val;
++}
++EXPORT_SYMBOL_GPL(clk_mux_reindex);
++
++static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
++{
++	struct clk_mux *mux = to_clk_mux(hw);
++	u32 val;
++	unsigned long flags = 0;
++
++	index = clk_mux_reindex(index, mux->table, mux->flags);
++
+	if (mux->lock)
+		spin_lock_irqsave(mux->lock, flags);
+	else
+@@ -102,14 +121,14 @@ static int clk_mux_set_parent(struct clk
+ }
+
+ const struct clk_ops clk_mux_ops = {
+-	.get_parent = clk_mux_get_parent,
++	.get_parent = _clk_mux_get_parent,
+	.set_parent = clk_mux_set_parent,
+	.determine_rate = __clk_mux_determine_rate,
+ };
+ EXPORT_SYMBOL_GPL(clk_mux_ops);
+
+ const struct clk_ops clk_mux_ro_ops = {
+-	.get_parent = clk_mux_get_parent,
++	.get_parent = _clk_mux_get_parent,
+ };
+ EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
+
+@@ -117,7 +136,7 @@ struct clk_hw *clk_hw_register_mux_table
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u32 mask,
+-		u8 clk_mux_flags, u32 *table, spinlock_t *lock)
++		u8 clk_mux_flags, unsigned int *table, spinlock_t *lock)
+ {
+	struct clk_mux *mux;
+	struct clk_hw *hw;
+--- a/include/linux/clk-provider.h
++++ b/include/linux/clk-provider.h
+@@ -468,7 +468,7 @@ void clk_hw_unregister_divider(struct cl
+ struct clk_mux {
+	struct clk_hw	hw;
+	void __iomem	*reg;
+-	u32		*table;
++	unsigned int	*table;
+	u32		mask;
+	u8		shift;
+	u8		flags;
+@@ -486,6 +486,11 @@ struct clk_mux {
+ extern const struct clk_ops clk_mux_ops;
+ extern const struct clk_ops clk_mux_ro_ops;
+
++unsigned int clk_mux_get_parent(struct clk_hw *hw, unsigned int val,
++				unsigned int *table, unsigned long flags);
++unsigned int clk_mux_reindex(u8 index, unsigned int *table,
++			     unsigned long flags);
++
+ struct clk *clk_register_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+@@ -506,7 +511,7 @@ struct clk_hw *clk_hw_register_mux_table
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags,
+		void __iomem *reg, u8 shift, u32 mask,
+-		u8 clk_mux_flags, u32 *table, spinlock_t *lock);
++		u8 clk_mux_flags, unsigned int *table, spinlock_t *lock);
+
+ void clk_unregister_mux(struct clk *clk);
+ void clk_hw_unregister_mux(struct clk_hw *hw);
diff --git a/target/linux/ipq806x/patches-4.14/0038-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch b/target/linux/ipq806x/patches-4.14/0038-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch
new file mode 100644
index 0000000..e0157d5
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0038-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch
@@ -0,0 +1,352 @@ 
+From patchwork Fri Dec  8 09:42:21 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,03/12] clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102083
+Message-Id: <1512726150-7204-4-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:21 +0530
+
+From: Stephen Boyd <sboyd@codeaurora.org>
+
+HFPLLs are the main frequency source for Krait CPU clocks. Add
+support for changing the rate of these PLLs.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/qcom/Makefile    |   1 +
+ drivers/clk/qcom/clk-hfpll.c | 253 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/clk/qcom/clk-hfpll.h |  54 +++++++++
+ 3 files changed, 308 insertions(+)
+ create mode 100644 drivers/clk/qcom/clk-hfpll.c
+ create mode 100644 drivers/clk/qcom/clk-hfpll.h
+
+--- a/drivers/clk/qcom/Makefile
++++ b/drivers/clk/qcom/Makefile
+@@ -10,6 +10,7 @@ clk-qcom-y += clk-rcg2.o
+ clk-qcom-y += clk-branch.o
+ clk-qcom-y += clk-regmap-divider.o
+ clk-qcom-y += clk-regmap-mux.o
++clk-qcom-y += clk-hfpll.o
+ clk-qcom-y += reset.o
+ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
+
+--- /dev/null
++++ b/drivers/clk/qcom/clk-hfpll.c
+@@ -0,0 +1,253 @@
++/*
++ * Copyright (c) 2013-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++#include <linux/kernel.h>
++#include <linux/export.h>
++#include <linux/regmap.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/clk-provider.h>
++#include <linux/spinlock.h>
++
++#include "clk-regmap.h"
++#include "clk-hfpll.h"
++
++#define PLL_OUTCTRL	BIT(0)
++#define PLL_BYPASSNL	BIT(1)
++#define PLL_RESET_N	BIT(2)
++
++/* Initialize a HFPLL at a given rate and enable it. */
++static void __clk_hfpll_init_once(struct clk_hw *hw)
++{
++	struct clk_hfpll *h = to_clk_hfpll(hw);
++	struct hfpll_data const *hd = h->d;
++	struct regmap *regmap = h->clkr.regmap;
++
++	if (likely(h->init_done))
++		return;
++
++	/* Configure PLL parameters for integer mode. */
++	if (hd->config_val)
++		regmap_write(regmap, hd->config_reg, hd->config_val);
++	regmap_write(regmap, hd->m_reg, 0);
++	regmap_write(regmap, hd->n_reg, 1);
++
++	if (hd->user_reg) {
++		u32 regval = hd->user_val;
++		unsigned long rate;
++
++		rate = clk_hw_get_rate(hw);
++
++		/* Pick the right VCO. */
++		if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
++			regval |= hd->user_vco_mask;
++		regmap_write(regmap, hd->user_reg, regval);
++	}
++
++	if (hd->droop_reg)
++		regmap_write(regmap, hd->droop_reg, hd->droop_val);
++
++	h->init_done = true;
++}
++
++static void __clk_hfpll_enable(struct clk_hw *hw)
++{
++	struct clk_hfpll *h = to_clk_hfpll(hw);
++	struct hfpll_data const *hd = h->d;
++	struct regmap *regmap = h->clkr.regmap;
++	u32 val;
++
++	__clk_hfpll_init_once(hw);
++
++	/* Disable PLL bypass mode. */
++	regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);
++
++	/*
++	 * H/W requires a 5us delay between disabling the bypass and
++	 * de-asserting the reset. Delay 10us just to be safe.
++	 */
++	usleep_range(10, 100);
++
++	/* De-assert active-low PLL reset. */
++	regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
++
++	/* Wait for PLL to lock. */
++	if (hd->status_reg) {
++		do {
++			regmap_read(regmap, hd->status_reg, &val);
++		} while (!(val & BIT(hd->lock_bit)));
++	} else {
++		usleep_range(60, 100);
++	}
++
++	/* Enable PLL output. */
++	regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
++}
++
++/* Enable an already-configured HFPLL. */
++static int clk_hfpll_enable(struct clk_hw *hw)
++{
++	unsigned long flags;
++	struct clk_hfpll *h = to_clk_hfpll(hw);
++	struct hfpll_data const *hd = h->d;
++	struct regmap *regmap = h->clkr.regmap;
++	u32 mode;
++
++	spin_lock_irqsave(&h->lock, flags);
++	regmap_read(regmap, hd->mode_reg, &mode);
++	if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
++		__clk_hfpll_enable(hw);
++	spin_unlock_irqrestore(&h->lock, flags);
++
++	return 0;
++}
++
++static void __clk_hfpll_disable(struct clk_hfpll *h)
++{
++	struct hfpll_data const *hd = h->d;
++	struct regmap *regmap = h->clkr.regmap;
++
++	/*
++	 * Disable the PLL output, disable test mode, enable the bypass mode,
++	 * and assert the reset.
++	 */
++	regmap_update_bits(regmap, hd->mode_reg,
++			   PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
++}
++
++static void clk_hfpll_disable(struct clk_hw *hw)
++{
++	struct clk_hfpll *h = to_clk_hfpll(hw);
++	unsigned long flags;
++
++	spin_lock_irqsave(&h->lock, flags);
++	__clk_hfpll_disable(h);
++	spin_unlock_irqrestore(&h->lock, flags);
++}
++
++static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate,
++				 unsigned long *parent_rate)
++{
++	struct clk_hfpll *h = to_clk_hfpll(hw);
++	struct hfpll_data const *hd = h->d;
++	unsigned long rrate;
++
++	rate = clamp(rate, hd->min_rate, hd->max_rate);
++
++	rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate;
++	if (rrate > hd->max_rate)
++		rrate -= *parent_rate;
++
++	return rrate;
++}
++
++/*
++ * For optimization reasons, assumes no downstream clocks are actively using
++ * it.
++ */
++static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
++			      unsigned long parent_rate)
++{
++	struct clk_hfpll *h = to_clk_hfpll(hw);
++	struct hfpll_data const *hd = h->d;
++	struct regmap *regmap = h->clkr.regmap;
++	unsigned long flags;
++	u32 l_val, val;
++	bool enabled;
++
++	l_val = rate / parent_rate;
++
++	spin_lock_irqsave(&h->lock, flags);
++
++	enabled = __clk_is_enabled(hw->clk);
++	if (enabled)
++		__clk_hfpll_disable(h);
++
++	/* Pick the right VCO. */
++	if (hd->user_reg && hd->user_vco_mask) {
++		regmap_read(regmap, hd->user_reg, &val);
++		if (rate <= hd->low_vco_max_rate)
++			val &= ~hd->user_vco_mask;
++		else
++			val |= hd->user_vco_mask;
++		regmap_write(regmap, hd->user_reg, val);
++	}
++
++	regmap_write(regmap, hd->l_reg, l_val);
++
++	if (enabled)
++		__clk_hfpll_enable(hw);
++
++	spin_unlock_irqrestore(&h->lock, flags);
++
++	return 0;
++}
++
++static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
++					   unsigned long parent_rate)
++{
++	struct clk_hfpll *h = to_clk_hfpll(hw);
++	struct hfpll_data const *hd = h->d;
++	struct regmap *regmap = h->clkr.regmap;
++	u32 l_val;
++
++	regmap_read(regmap, hd->l_reg, &l_val);
++
++	return l_val * parent_rate;
++}
++
++static void clk_hfpll_init(struct clk_hw *hw)
++{
++	struct clk_hfpll *h = to_clk_hfpll(hw);
++	struct hfpll_data const *hd = h->d;
++	struct regmap *regmap = h->clkr.regmap;
++	u32 mode, status;
++
++	regmap_read(regmap, hd->mode_reg, &mode);
++	if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
++		__clk_hfpll_init_once(hw);
++		return;
++	}
++
++	if (hd->status_reg) {
++		regmap_read(regmap, hd->status_reg, &status);
++		if (!(status & BIT(hd->lock_bit))) {
++			WARN(1, "HFPLL %s is ON, but not locked!\n",
++			     __clk_get_name(hw->clk));
++			clk_hfpll_disable(hw);
++			__clk_hfpll_init_once(hw);
++		}
++	}
++}
++
++static int hfpll_is_enabled(struct clk_hw *hw)
++{
++	struct clk_hfpll *h = to_clk_hfpll(hw);
++	struct hfpll_data const *hd = h->d;
++	struct regmap *regmap = h->clkr.regmap;
++	u32 mode;
++
++	regmap_read(regmap, hd->mode_reg, &mode);
++	mode &= 0x7;
++	return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
++}
++
++const struct clk_ops clk_ops_hfpll = {
++	.enable = clk_hfpll_enable,
++	.disable = clk_hfpll_disable,
++	.is_enabled = hfpll_is_enabled,
++	.round_rate = clk_hfpll_round_rate,
++	.set_rate = clk_hfpll_set_rate,
++	.recalc_rate = clk_hfpll_recalc_rate,
++	.init = clk_hfpll_init,
++};
++EXPORT_SYMBOL_GPL(clk_ops_hfpll);
+--- /dev/null
++++ b/drivers/clk/qcom/clk-hfpll.h
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (c) 2013-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++#ifndef __QCOM_CLK_HFPLL_H__
++#define __QCOM_CLK_HFPLL_H__
++
++#include <linux/clk-provider.h>
++#include <linux/spinlock.h>
++#include "clk-regmap.h"
++
++struct hfpll_data {
++	u32 mode_reg;
++	u32 l_reg;
++	u32 m_reg;
++	u32 n_reg;
++	u32 user_reg;
++	u32 droop_reg;
++	u32 config_reg;
++	u32 status_reg;
++	u8  lock_bit;
++
++	u32 droop_val;
++	u32 config_val;
++	u32 user_val;
++	u32 user_vco_mask;
++	unsigned long low_vco_max_rate;
++
++	unsigned long min_rate;
++	unsigned long max_rate;
++};
++
++struct clk_hfpll {
++	struct hfpll_data const *d;
++	int init_done;
++
++	struct clk_regmap clkr;
++	spinlock_t lock;
++};
++
++#define to_clk_hfpll(_hw) \
++	container_of(to_clk_regmap(_hw), struct clk_hfpll, clkr)
++
++extern const struct clk_ops clk_ops_hfpll;
++
++#endif
diff --git a/target/linux/ipq806x/patches-4.14/0039-clk-qcom-Add-HFPLL-driver.patch b/target/linux/ipq806x/patches-4.14/0039-clk-qcom-Add-HFPLL-driver.patch
new file mode 100644
index 0000000..8f50240
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0039-clk-qcom-Add-HFPLL-driver.patch
@@ -0,0 +1,206 @@ 
+From patchwork Fri Dec  8 09:42:22 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,04/12] clk: qcom: Add HFPLL driver
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102079
+Message-Id: <1512726150-7204-5-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:22 +0530
+
+From: Stephen Boyd <sboyd@codeaurora.org>
+
+On some devices (MSM8974 for example), the HFPLLs are
+instantiated within the Krait processor subsystem as separate
+register regions. Add a driver for these PLLs so that we can
+provide HFPLL clocks for use by the system.
+
+Cc: <devicetree@vger.kernel.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ .../devicetree/bindings/clock/qcom,hfpll.txt       |  40 ++++++++
+ drivers/clk/qcom/Kconfig                           |   8 ++
+ drivers/clk/qcom/Makefile                          |   1 +
+ drivers/clk/qcom/hfpll.c                           | 106 +++++++++++++++++++++
+ 4 files changed, 155 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/clock/qcom,hfpll.txt
+ create mode 100644 drivers/clk/qcom/hfpll.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/clock/qcom,hfpll.txt
+@@ -0,0 +1,40 @@
++High-Frequency PLL (HFPLL)
++
++PROPERTIES
++
++- compatible:
++	Usage: required
++	Value type: <string>
++	Definition: must be "qcom,hfpll"
++
++- reg:
++	Usage: required
++	Value type: <prop-encoded-array>
++	Definition: address and size of HPLL registers. An optional second
++		    element specifies the address and size of the alias
++		    register region.
++
++- clock-output-names:
++	Usage: required
++	Value type: <string>
++	Definition: Name of the PLL. Typically hfpllX where X is a CPU number
++		    starting at 0. Otherwise hfpll_Y where Y is more specific
++		    such as "l2".
++
++Example:
++
++1) An HFPLL for the L2 cache.
++
++	clock-controller@f9016000 {
++		compatible = "qcom,hfpll";
++		reg = <0xf9016000 0x30>;
++		clock-output-names = "hfpll_l2";
++	};
++
++2) An HFPLL for CPU0. This HFPLL has the alias register region.
++
++	clock-controller@f908a000 {
++		compatible = "qcom,hfpll";
++		reg = <0xf908a000 0x30>, <0xf900a000 0x30>;
++		clock-output-names = "hfpll0";
++	};
+--- a/drivers/clk/qcom/Kconfig
++++ b/drivers/clk/qcom/Kconfig
+@@ -196,3 +196,11 @@ config MSM_MMCC_8996
+	  Support for the multimedia clock controller on msm8996 devices.
+	  Say Y if you want to support multimedia devices such as display,
+	  graphics, video encode/decode, camera, etc.
++
++config QCOM_HFPLL
++	tristate "High-Frequency PLL (HFPLL) Clock Controller"
++	depends on COMMON_CLK_QCOM
++	help
++	  Support for the high-frequency PLLs present on Qualcomm devices.
++	  Say Y if you want to support CPU frequency scaling on devices
++	  such as MSM8974, APQ8084, etc.
+--- a/drivers/clk/qcom/Makefile
++++ b/drivers/clk/qcom/Makefile
+@@ -35,3 +35,4 @@ obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8
+ obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+ obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
+ obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
++obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
+--- /dev/null
++++ b/drivers/clk/qcom/hfpll.c
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (c) 2013-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/regmap.h>
++
++#include "clk-regmap.h"
++#include "clk-hfpll.h"
++
++static const struct hfpll_data hdata = {
++	.mode_reg = 0x00,
++	.l_reg = 0x04,
++	.m_reg = 0x08,
++	.n_reg = 0x0c,
++	.user_reg = 0x10,
++	.config_reg = 0x14,
++	.config_val = 0x430405d,
++	.status_reg = 0x1c,
++	.lock_bit = 16,
++
++	.user_val = 0x8,
++	.user_vco_mask = 0x100000,
++	.low_vco_max_rate = 1248000000,
++	.min_rate = 537600000UL,
++	.max_rate = 2900000000UL,
++};
++
++static const struct of_device_id qcom_hfpll_match_table[] = {
++	{ .compatible = "qcom,hfpll" },
++	{ }
++};
++MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table);
++
++static const struct regmap_config hfpll_regmap_config = {
++	.reg_bits	= 32,
++	.reg_stride	= 4,
++	.val_bits	= 32,
++	.max_register	= 0x30,
++	.fast_io	= true,
++};
++
++static int qcom_hfpll_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	struct device *dev = &pdev->dev;
++	void __iomem *base;
++	struct regmap *regmap;
++	struct clk_hfpll *h;
++	struct clk_init_data init = {
++		.parent_names = (const char *[]){ "xo" },
++		.num_parents = 1,
++		.ops = &clk_ops_hfpll,
++	};
++
++	h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
++	if (!h)
++		return -ENOMEM;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	base = devm_ioremap_resource(dev, res);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	regmap = devm_regmap_init_mmio(&pdev->dev, base, &hfpll_regmap_config);
++	if (IS_ERR(regmap))
++		return PTR_ERR(regmap);
++
++	if (of_property_read_string_index(dev->of_node, "clock-output-names",
++					  0, &init.name))
++		return -ENODEV;
++
++	h->d = &hdata;
++	h->clkr.hw.init = &init;
++	spin_lock_init(&h->lock);
++
++	return devm_clk_register_regmap(&pdev->dev, &h->clkr);
++}
++
++static struct platform_driver qcom_hfpll_driver = {
++	.probe		= qcom_hfpll_probe,
++	.driver		= {
++		.name	= "qcom-hfpll",
++		.of_match_table = qcom_hfpll_match_table,
++	},
++};
++module_platform_driver(qcom_hfpll_driver);
++
++MODULE_DESCRIPTION("QCOM HFPLL Clock Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:qcom-hfpll");
diff --git a/target/linux/ipq806x/patches-4.14/0040-clk-qcom-Add-IPQ806X-s-HFPLLs.patch b/target/linux/ipq806x/patches-4.14/0040-clk-qcom-Add-IPQ806X-s-HFPLLs.patch
new file mode 100644
index 0000000..f17e96d
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0040-clk-qcom-Add-IPQ806X-s-HFPLLs.patch
@@ -0,0 +1,129 @@ 
+From patchwork Fri Dec  8 09:42:24 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,06/12] clk: qcom: Add IPQ806X's HFPLLs
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102047
+Message-Id: <1512726150-7204-7-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:24 +0530
+
+From: Stephen Boyd <sboyd@codeaurora.org>
+
+Describe the HFPLLs present on IPQ806X devices.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/qcom/gcc-ipq806x.c | 82 ++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 82 insertions(+)
+
+--- a/drivers/clk/qcom/gcc-ipq806x.c
++++ b/drivers/clk/qcom/gcc-ipq806x.c
+@@ -30,6 +30,7 @@
+ #include "clk-pll.h"
+ #include "clk-rcg.h"
+ #include "clk-branch.h"
++#include "clk-hfpll.h"
+ #include "reset.h"
+
+ static struct clk_pll pll0 = {
+@@ -113,6 +114,84 @@ static struct clk_regmap pll8_vote = {
+	},
+ };
+
++static struct hfpll_data hfpll0_data = {
++	.mode_reg = 0x3200,
++	.l_reg = 0x3208,
++	.m_reg = 0x320c,
++	.n_reg = 0x3210,
++	.config_reg = 0x3204,
++	.status_reg = 0x321c,
++	.config_val = 0x7845c665,
++	.droop_reg = 0x3214,
++	.droop_val = 0x0108c000,
++	.min_rate = 600000000UL,
++	.max_rate = 1800000000UL,
++};
++
++static struct clk_hfpll hfpll0 = {
++	.d = &hfpll0_data,
++	.clkr.hw.init = &(struct clk_init_data){
++		.parent_names = (const char *[]){ "pxo" },
++		.num_parents = 1,
++		.name = "hfpll0",
++		.ops = &clk_ops_hfpll,
++		.flags = CLK_IGNORE_UNUSED,
++	},
++	.lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
++};
++
++static struct hfpll_data hfpll1_data = {
++	.mode_reg = 0x3240,
++	.l_reg = 0x3248,
++	.m_reg = 0x324c,
++	.n_reg = 0x3250,
++	.config_reg = 0x3244,
++	.status_reg = 0x325c,
++	.config_val = 0x7845c665,
++	.droop_reg = 0x3314,
++	.droop_val = 0x0108c000,
++	.min_rate = 600000000UL,
++	.max_rate = 1800000000UL,
++};
++
++static struct clk_hfpll hfpll1 = {
++	.d = &hfpll1_data,
++	.clkr.hw.init = &(struct clk_init_data){
++		.parent_names = (const char *[]){ "pxo" },
++		.num_parents = 1,
++		.name = "hfpll1",
++		.ops = &clk_ops_hfpll,
++		.flags = CLK_IGNORE_UNUSED,
++	},
++	.lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
++};
++
++static struct hfpll_data hfpll_l2_data = {
++	.mode_reg = 0x3300,
++	.l_reg = 0x3308,
++	.m_reg = 0x330c,
++	.n_reg = 0x3310,
++	.config_reg = 0x3304,
++	.status_reg = 0x331c,
++	.config_val = 0x7845c665,
++	.droop_reg = 0x3314,
++	.droop_val = 0x0108c000,
++	.min_rate = 600000000UL,
++	.max_rate = 1800000000UL,
++};
++
++static struct clk_hfpll hfpll_l2 = {
++	.d = &hfpll_l2_data,
++	.clkr.hw.init = &(struct clk_init_data){
++		.parent_names = (const char *[]){ "pxo" },
++		.num_parents = 1,
++		.name = "hfpll_l2",
++		.ops = &clk_ops_hfpll,
++		.flags = CLK_IGNORE_UNUSED,
++	},
++	.lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
++};
++
+ static struct clk_pll pll14 = {
+	.l_reg = 0x31c4,
+	.m_reg = 0x31c8,
+@@ -2801,6 +2880,9 @@ static struct clk_regmap *gcc_ipq806x_cl
+	[UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
+	[NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
+	[NSSTCM_CLK] = &nss_tcm_clk.clkr,
++	[PLL9] = &hfpll0.clkr,
++	[PLL10] = &hfpll1.clkr,
++	[PLL12] = &hfpll_l2.clkr,
+ };
+
+ static const struct qcom_reset_map gcc_ipq806x_resets[] = {
diff --git a/target/linux/ipq806x/patches-4.14/0041-clk-qcom-Add-support-for-Krait-clocks.patch b/target/linux/ipq806x/patches-4.14/0041-clk-qcom-Add-support-for-Krait-clocks.patch
new file mode 100644
index 0000000..2a55dde
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0041-clk-qcom-Add-support-for-Krait-clocks.patch
@@ -0,0 +1,241 @@ 
+From patchwork Fri Dec  8 09:42:25 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,07/12] clk: qcom: Add support for Krait clocks
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102051
+Message-Id: <1512726150-7204-8-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:25 +0530
+
+From: Stephen Boyd <sboyd@codeaurora.org>
+
+The Krait clocks are made up of a series of muxes and a divider
+that choose between a fixed rate clock and dedicated HFPLLs for
+each CPU. Instead of using mmio accesses to remux parents, the
+Krait implementation exposes the remux control via cp15
+registers. Support these clocks.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ drivers/clk/qcom/Kconfig     |   4 ++
+ drivers/clk/qcom/Makefile    |   1 +
+ drivers/clk/qcom/clk-krait.c | 134 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/clk/qcom/clk-krait.h |  48 ++++++++++++++++
+ 4 files changed, 187 insertions(+)
+ create mode 100644 drivers/clk/qcom/clk-krait.c
+ create mode 100644 drivers/clk/qcom/clk-krait.h
+
+--- a/drivers/clk/qcom/Kconfig
++++ b/drivers/clk/qcom/Kconfig
+@@ -204,3 +204,7 @@ config QCOM_HFPLL
+	  Support for the high-frequency PLLs present on Qualcomm devices.
+	  Say Y if you want to support CPU frequency scaling on devices
+	  such as MSM8974, APQ8084, etc.
++
++config KRAIT_CLOCKS
++	bool
++	select KRAIT_L2_ACCESSORS
+--- a/drivers/clk/qcom/Makefile
++++ b/drivers/clk/qcom/Makefile
+@@ -10,6 +10,7 @@ clk-qcom-y += clk-rcg2.o
+ clk-qcom-y += clk-branch.o
+ clk-qcom-y += clk-regmap-divider.o
+ clk-qcom-y += clk-regmap-mux.o
++clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
+ clk-qcom-y += clk-hfpll.o
+ clk-qcom-y += reset.o
+ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
+--- /dev/null
++++ b/drivers/clk/qcom/clk-krait.c
+@@ -0,0 +1,134 @@
++/*
++ * Copyright (c) 2013-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/clk-provider.h>
++#include <linux/spinlock.h>
++
++#include <asm/krait-l2-accessors.h>
++
++#include "clk-krait.h"
++
++/* Secondary and primary muxes share the same cp15 register */
++static DEFINE_SPINLOCK(krait_clock_reg_lock);
++
++#define LPL_SHIFT	8
++static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel)
++{
++	unsigned long flags;
++	u32 regval;
++
++	spin_lock_irqsave(&krait_clock_reg_lock, flags);
++	regval = krait_get_l2_indirect_reg(mux->offset);
++	regval &= ~(mux->mask << mux->shift);
++	regval |= (sel & mux->mask) << mux->shift;
++	if (mux->lpl) {
++		regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
++		regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
++	}
++	krait_set_l2_indirect_reg(mux->offset, regval);
++	spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
++
++	/* Wait for switch to complete. */
++	mb();
++	udelay(1);
++}
++
++static int krait_mux_set_parent(struct clk_hw *hw, u8 index)
++{
++	struct krait_mux_clk *mux = to_krait_mux_clk(hw);
++	u32 sel;
++
++	sel = clk_mux_reindex(index, mux->parent_map, 0);
++	mux->en_mask = sel;
++	/* Don't touch mux if CPU is off as it won't work */
++	if (__clk_is_enabled(hw->clk))
++		__krait_mux_set_sel(mux, sel);
++
++	return 0;
++}
++
++static u8 krait_mux_get_parent(struct clk_hw *hw)
++{
++	struct krait_mux_clk *mux = to_krait_mux_clk(hw);
++	u32 sel;
++
++	sel = krait_get_l2_indirect_reg(mux->offset);
++	sel >>= mux->shift;
++	sel &= mux->mask;
++	mux->en_mask = sel;
++
++	return clk_mux_get_parent(hw, sel, mux->parent_map, 0);
++}
++
++const struct clk_ops krait_mux_clk_ops = {
++	.set_parent = krait_mux_set_parent,
++	.get_parent = krait_mux_get_parent,
++	.determine_rate = __clk_mux_determine_rate_closest,
++};
++EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
++
++/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
++static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate,
++				  unsigned long *parent_rate)
++{
++	*parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), rate * 2);
++	return DIV_ROUND_UP(*parent_rate, 2);
++}
++
++static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,
++			       unsigned long parent_rate)
++{
++	struct krait_div2_clk *d = to_krait_div2_clk(hw);
++	unsigned long flags;
++	u32 val;
++	u32 mask = BIT(d->width) - 1;
++
++	if (d->lpl)
++		mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift;
++
++	spin_lock_irqsave(&krait_clock_reg_lock, flags);
++	val = krait_get_l2_indirect_reg(d->offset);
++	val &= ~mask;
++	krait_set_l2_indirect_reg(d->offset, val);
++	spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
++
++	return 0;
++}
++
++static unsigned long
++krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
++{
++	struct krait_div2_clk *d = to_krait_div2_clk(hw);
++	u32 mask = BIT(d->width) - 1;
++	u32 div;
++
++	div = krait_get_l2_indirect_reg(d->offset);
++	div >>= d->shift;
++	div &= mask;
++	div = (div + 1) * 2;
++
++	return DIV_ROUND_UP(parent_rate, div);
++}
++
++const struct clk_ops krait_div2_clk_ops = {
++	.round_rate = krait_div2_round_rate,
++	.set_rate = krait_div2_set_rate,
++	.recalc_rate = krait_div2_recalc_rate,
++};
++EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
+--- /dev/null
++++ b/drivers/clk/qcom/clk-krait.h
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (c) 2013, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __QCOM_CLK_KRAIT_H
++#define __QCOM_CLK_KRAIT_H
++
++#include <linux/clk-provider.h>
++
++struct krait_mux_clk {
++	unsigned int	*parent_map;
++	u32		offset;
++	u32		mask;
++	u32		shift;
++	u32		en_mask;
++	bool		lpl;
++
++	struct clk_hw	hw;
++	struct notifier_block   clk_nb;
++};
++
++#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)
++
++extern const struct clk_ops krait_mux_clk_ops;
++
++struct krait_div2_clk {
++	u32		offset;
++	u8		width;
++	u32		shift;
++	bool		lpl;
++
++	struct clk_hw	hw;
++};
++
++#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw)
++
++extern const struct clk_ops krait_div2_clk_ops;
++
++#endif
diff --git a/target/linux/ipq806x/patches-4.14/0042-clk-qcom-Add-KPSS-ACC-GCC-driver.patch b/target/linux/ipq806x/patches-4.14/0042-clk-qcom-Add-KPSS-ACC-GCC-driver.patch
new file mode 100644
index 0000000..8846dba
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0042-clk-qcom-Add-KPSS-ACC-GCC-driver.patch
@@ -0,0 +1,209 @@ 
+From patchwork Fri Dec  8 09:42:26 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,08/12] clk: qcom: Add KPSS ACC/GCC driver
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102023
+Message-Id: <1512726150-7204-9-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:26 +0530
+
+From: Stephen Boyd <sboyd@codeaurora.org>
+
+The ACC and GCC regions present in KPSSv1 contain registers to
+control clocks and power to each Krait CPU and L2. For CPUfreq
+purposes probe these devices and expose a mux clock that chooses
+between PXO and PLL8.
+
+Cc: <devicetree@vger.kernel.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ .../devicetree/bindings/arm/msm/qcom,kpss-acc.txt  |  7 ++
+ .../devicetree/bindings/arm/msm/qcom,kpss-gcc.txt  | 28 +++++++
+ drivers/clk/qcom/Kconfig                           |  8 ++
+ drivers/clk/qcom/Makefile                          |  1 +
+ drivers/clk/qcom/kpss-xcc.c                        | 96 ++++++++++++++++++++++
+ 5 files changed, 140 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
+ create mode 100644 drivers/clk/qcom/kpss-xcc.c
+
+--- a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt
++++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt
+@@ -21,10 +21,17 @@ PROPERTIES
+		    the register region. An optional second element specifies
+		    the base address and size of the alias register region.
+
++- clock-output-names:
++	Usage: optional
++	Value type: <string>
++	Definition: Name of the output clock. Typically acpuX_aux where X is a
++		    CPU number starting at 0.
++
+ Example:
+
+	clock-controller@2088000 {
+		compatible = "qcom,kpss-acc-v2";
+		reg = <0x02088000 0x1000>,
+		      <0x02008000 0x1000>;
++		clock-output-names = "acpu0_aux";
+	};
+--- /dev/null
++++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
+@@ -0,0 +1,28 @@
++Krait Processor Sub-system (KPSS) Global Clock Controller (GCC)
++
++PROPERTIES
++
++- compatible:
++	Usage: required
++	Value type: <string>
++	Definition: should be one of:
++			"qcom,kpss-gcc"
++
++- reg:
++	Usage: required
++	Value type: <prop-encoded-array>
++	Definition: base address and size of the register region
++
++- clock-output-names:
++	Usage: required
++	Value type: <string>
++	Definition: Name of the output clock. Typically acpu_l2_aux indicating
++		    an L2 cache auxiliary clock.
++
++Example:
++
++	l2cc: clock-controller@2011000 {
++		compatible = "qcom,kpss-gcc";
++		reg = <0x2011000 0x1000>;
++		clock-output-names = "acpu_l2_aux";
++	};
+--- a/drivers/clk/qcom/Kconfig
++++ b/drivers/clk/qcom/Kconfig
+@@ -205,6 +205,14 @@ config QCOM_HFPLL
+	  Say Y if you want to support CPU frequency scaling on devices
+	  such as MSM8974, APQ8084, etc.
+
++config KPSS_XCC
++	tristate "KPSS Clock Controller"
++	depends on COMMON_CLK_QCOM
++	help
++	  Support for the Krait ACC and GCC clock controllers. Say Y
++	  if you want to support CPU frequency scaling on devices such
++	  as MSM8960, APQ8064, etc.
++
+ config KRAIT_CLOCKS
+	bool
+	select KRAIT_L2_ACCESSORS
+--- a/drivers/clk/qcom/Makefile
++++ b/drivers/clk/qcom/Makefile
+@@ -36,4 +36,5 @@ obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8
+ obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+ obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
+ obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
++obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
+ obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
+--- /dev/null
++++ b/drivers/clk/qcom/kpss-xcc.c
+@@ -0,0 +1,96 @@
++/* Copyright (c) 2014-2015, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++
++static const char *aux_parents[] = {
++	"pll8_vote",
++	"pxo",
++};
++
++static unsigned int aux_parent_map[] = {
++	3,
++	0,
++};
++
++static const struct of_device_id kpss_xcc_match_table[] = {
++	{ .compatible = "qcom,kpss-acc-v1", .data = (void *)1UL },
++	{ .compatible = "qcom,kpss-gcc" },
++	{}
++};
++MODULE_DEVICE_TABLE(of, kpss_xcc_match_table);
++
++static int kpss_xcc_driver_probe(struct platform_device *pdev)
++{
++	const struct of_device_id *id;
++	struct clk *clk;
++	struct resource *res;
++	void __iomem *base;
++	const char *name;
++
++	id = of_match_device(kpss_xcc_match_table, &pdev->dev);
++	if (!id)
++		return -ENODEV;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	base = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	if (id->data) {
++		if (of_property_read_string_index(pdev->dev.of_node,
++						  "clock-output-names",
++						  0, &name))
++			return -ENODEV;
++		base += 0x14;
++	} else {
++		name = "acpu_l2_aux";
++		base += 0x28;
++	}
++
++	clk = clk_register_mux_table(&pdev->dev, name, aux_parents,
++				     ARRAY_SIZE(aux_parents), 0, base, 0, 0x3,
++				     0, aux_parent_map, NULL);
++
++	platform_set_drvdata(pdev, clk);
++
++	return PTR_ERR_OR_ZERO(clk);
++}
++
++static int kpss_xcc_driver_remove(struct platform_device *pdev)
++{
++	clk_unregister_mux(platform_get_drvdata(pdev));
++	return 0;
++}
++
++static struct platform_driver kpss_xcc_driver = {
++	.probe = kpss_xcc_driver_probe,
++	.remove = kpss_xcc_driver_remove,
++	.driver = {
++		.name = "kpss-xcc",
++		.of_match_table = kpss_xcc_match_table,
++	},
++};
++module_platform_driver(kpss_xcc_driver);
++
++MODULE_DESCRIPTION("Krait Processor Sub System (KPSS) Clock Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:kpss-xcc");
diff --git a/target/linux/ipq806x/patches-4.14/0043-clk-qcom-Add-Krait-clock-controller-driver.patch b/target/linux/ipq806x/patches-4.14/0043-clk-qcom-Add-Krait-clock-controller-driver.patch
new file mode 100644
index 0000000..00bdcec
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0043-clk-qcom-Add-Krait-clock-controller-driver.patch
@@ -0,0 +1,436 @@ 
+From patchwork Fri Dec  8 09:42:27 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,09/12] clk: qcom: Add Krait clock controller driver
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102061
+Message-Id: <1512726150-7204-10-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:27 +0530
+
+From: Stephen Boyd <sboyd@codeaurora.org>
+
+The Krait CPU clocks are made up of a primary mux and secondary
+mux for each CPU and the L2, controlled via cp15 accessors. For
+Kraits within KPSSv1 each secondary mux accepts a different aux
+source, but on KPSSv2 each secondary mux accepts the same aux
+source.
+
+Cc: <devicetree@vger.kernel.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ .../devicetree/bindings/clock/qcom,krait-cc.txt    |  22 ++
+ drivers/clk/qcom/Kconfig                           |   8 +
+ drivers/clk/qcom/Makefile                          |   1 +
+ drivers/clk/qcom/krait-cc.c                        | 350 +++++++++++++++++++++
+ 4 files changed, 381 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
+ create mode 100644 drivers/clk/qcom/krait-cc.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
+@@ -0,0 +1,22 @@
++Krait Clock Controller
++
++PROPERTIES
++
++- compatible:
++	Usage: required
++	Value type: <string>
++	Definition: must be one of:
++			"qcom,krait-cc-v1"
++			"qcom,krait-cc-v2"
++
++- #clock-cells:
++	Usage: required
++	Value type: <u32>
++	Definition: must be 1
++
++Example:
++
++	kraitcc: clock-controller {
++		compatible = "qcom,krait-cc-v1";
++		#clock-cells = <1>;
++	};
+--- a/drivers/clk/qcom/Kconfig
++++ b/drivers/clk/qcom/Kconfig
+@@ -213,6 +213,14 @@ config KPSS_XCC
+	  if you want to support CPU frequency scaling on devices such
+	  as MSM8960, APQ8064, etc.
+
++config KRAITCC
++	tristate "Krait Clock Controller"
++	depends on COMMON_CLK_QCOM && ARM
++	select KRAIT_CLOCKS
++	help
++	  Support for the Krait CPU clocks on Qualcomm devices.
++	  Say Y if you want to support CPU frequency scaling.
++
+ config KRAIT_CLOCKS
+	bool
+	select KRAIT_L2_ACCESSORS
+--- a/drivers/clk/qcom/Makefile
++++ b/drivers/clk/qcom/Makefile
+@@ -38,3 +38,4 @@ obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
+ obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
+ obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
+ obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
++obj-$(CONFIG_KRAITCC) += krait-cc.o
+--- /dev/null
++++ b/drivers/clk/qcom/krait-cc.c
+@@ -0,0 +1,350 @@
++/* Copyright (c) 2013-2015, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/clk.h>
++#include <linux/clk-provider.h>
++#include <linux/slab.h>
++
++#include "clk-krait.h"
++
++static unsigned int sec_mux_map[] = {
++	2,
++	0,
++};
++
++static unsigned int pri_mux_map[] = {
++	1,
++	2,
++	0,
++};
++
++static int
++krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
++{
++	struct krait_div2_clk *div;
++	struct clk_init_data init = {
++		.num_parents = 1,
++		.ops = &krait_div2_clk_ops,
++		.flags = CLK_SET_RATE_PARENT,
++	};
++	const char *p_names[1];
++	struct clk *clk;
++
++	div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
++	if (!div)
++		return -ENOMEM;
++
++	div->width = 2;
++	div->shift = 6;
++	div->lpl = id >= 0;
++	div->offset = offset;
++	div->hw.init = &init;
++
++	init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
++	if (!init.name)
++		return -ENOMEM;
++
++	init.parent_names = p_names;
++	p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
++	if (!p_names[0]) {
++		kfree(init.name);
++		return -ENOMEM;
++	}
++
++	clk = devm_clk_register(dev, &div->hw);
++	kfree(p_names[0]);
++	kfree(init.name);
++
++	return PTR_ERR_OR_ZERO(clk);
++}
++
++static int
++krait_add_sec_mux(struct device *dev, int id, const char *s,
++		  unsigned int offset, bool unique_aux)
++{
++	struct krait_mux_clk *mux;
++	static const char *sec_mux_list[] = {
++		"acpu_aux",
++		"qsb",
++	};
++	struct clk_init_data init = {
++		.parent_names = sec_mux_list,
++		.num_parents = ARRAY_SIZE(sec_mux_list),
++		.ops = &krait_mux_clk_ops,
++		.flags = CLK_SET_RATE_PARENT,
++	};
++	struct clk *clk;
++
++	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
++	if (!mux)
++		return -ENOMEM;
++
++	mux->offset = offset;
++	mux->lpl = id >= 0;
++	mux->mask = 0x3;
++	mux->shift = 2;
++	mux->parent_map = sec_mux_map;
++	mux->hw.init = &init;
++
++	init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
++	if (!init.name)
++		return -ENOMEM;
++
++	if (unique_aux) {
++		sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s);
++		if (!sec_mux_list[0]) {
++			clk = ERR_PTR(-ENOMEM);
++			goto err_aux;
++		}
++	}
++
++	clk = devm_clk_register(dev, &mux->hw);
++
++	if (unique_aux)
++		kfree(sec_mux_list[0]);
++err_aux:
++	kfree(init.name);
++	return PTR_ERR_OR_ZERO(clk);
++}
++
++static struct clk *
++krait_add_pri_mux(struct device *dev, int id, const char *s,
++		  unsigned int offset)
++{
++	struct krait_mux_clk *mux;
++	const char *p_names[3];
++	struct clk_init_data init = {
++		.parent_names = p_names,
++		.num_parents = ARRAY_SIZE(p_names),
++		.ops = &krait_mux_clk_ops,
++		.flags = CLK_SET_RATE_PARENT,
++	};
++	struct clk *clk;
++
++	mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
++	if (!mux)
++		return ERR_PTR(-ENOMEM);
++
++	mux->mask = 0x3;
++	mux->shift = 0;
++	mux->offset = offset;
++	mux->lpl = id >= 0;
++	mux->parent_map = pri_mux_map;
++	mux->hw.init = &init;
++
++	init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
++	if (!init.name)
++		return ERR_PTR(-ENOMEM);
++
++	p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
++	if (!p_names[0]) {
++		clk = ERR_PTR(-ENOMEM);
++		goto err_p0;
++	}
++
++	p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
++	if (!p_names[1]) {
++		clk = ERR_PTR(-ENOMEM);
++		goto err_p1;
++	}
++
++	p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
++	if (!p_names[2]) {
++		clk = ERR_PTR(-ENOMEM);
++		goto err_p2;
++	}
++
++	clk = devm_clk_register(dev, &mux->hw);
++
++	kfree(p_names[2]);
++err_p2:
++	kfree(p_names[1]);
++err_p1:
++	kfree(p_names[0]);
++err_p0:
++	kfree(init.name);
++	return clk;
++}
++
++/* id < 0 for L2, otherwise id == physical CPU number */
++static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux)
++{
++	int ret;
++	unsigned int offset;
++	void *p = NULL;
++	const char *s;
++	struct clk *clk;
++
++	if (id >= 0) {
++		offset = 0x4501 + (0x1000 * id);
++		s = p = kasprintf(GFP_KERNEL, "%d", id);
++		if (!s)
++			return ERR_PTR(-ENOMEM);
++	} else {
++		offset = 0x500;
++		s = "_l2";
++	}
++
++	ret = krait_add_div(dev, id, s, offset);
++	if (ret) {
++		clk = ERR_PTR(ret);
++		goto err;
++	}
++
++	ret = krait_add_sec_mux(dev, id, s, offset, unique_aux);
++	if (ret) {
++		clk = ERR_PTR(ret);
++		goto err;
++	}
++
++	clk = krait_add_pri_mux(dev, id, s, offset);
++err:
++	kfree(p);
++	return clk;
++}
++
++static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data)
++{
++	unsigned int idx = clkspec->args[0];
++	struct clk **clks = data;
++
++	if (idx >= 5) {
++		pr_err("%s: invalid clock index %d\n", __func__, idx);
++		return ERR_PTR(-EINVAL);
++	}
++
++	return clks[idx] ? : ERR_PTR(-ENODEV);
++}
++
++static const struct of_device_id krait_cc_match_table[] = {
++	{ .compatible = "qcom,krait-cc-v1", (void *)1UL },
++	{ .compatible = "qcom,krait-cc-v2" },
++	{}
++};
++MODULE_DEVICE_TABLE(of, krait_cc_match_table);
++
++static int krait_cc_probe(struct platform_device *pdev)
++{
++	struct device *dev = &pdev->dev;
++	const struct of_device_id *id;
++	unsigned long cur_rate, aux_rate;
++	int cpu;
++	struct clk *clk;
++	struct clk **clks;
++	struct clk *l2_pri_mux_clk;
++
++	id = of_match_device(krait_cc_match_table, dev);
++	if (!id)
++		return -ENODEV;
++
++	/* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */
++	clk = clk_register_fixed_rate(dev, "qsb", NULL, 0, 1);
++	if (IS_ERR(clk))
++		return PTR_ERR(clk);
++
++	if (!id->data) {
++		clk = clk_register_fixed_factor(dev, "acpu_aux",
++						"gpll0_vote", 0, 1, 2);
++		if (IS_ERR(clk))
++			return PTR_ERR(clk);
++	}
++
++	/* Krait configurations have at most 4 CPUs and one L2 */
++	clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL);
++	if (!clks)
++		return -ENOMEM;
++
++	for_each_possible_cpu(cpu) {
++		clk = krait_add_clks(dev, cpu, id->data);
++		if (IS_ERR(clk))
++			return PTR_ERR(clk);
++		clks[cpu] = clk;
++	}
++
++	l2_pri_mux_clk = krait_add_clks(dev, -1, id->data);
++	if (IS_ERR(l2_pri_mux_clk))
++		return PTR_ERR(l2_pri_mux_clk);
++	clks[4] = l2_pri_mux_clk;
++
++	/*
++	 * We don't want the CPU or L2 clocks to be turned off at late init
++	 * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
++	 * refcount of these clocks. Any cpufreq/hotplug manager can assume
++	 * that the clocks have already been prepared and enabled by the time
++	 * they take over.
++	 */
++	for_each_online_cpu(cpu) {
++		clk_prepare_enable(l2_pri_mux_clk);
++		WARN(clk_prepare_enable(clks[cpu]),
++		     "Unable to turn on CPU%d clock", cpu);
++	}
++
++	/*
++	 * Force reinit of HFPLLs and muxes to overwrite any potential
++	 * incorrect configuration of HFPLLs and muxes by the bootloader.
++	 * While at it, also make sure the cores are running at known rates
++	 * and print the current rate.
++	 *
++	 * The clocks are set to aux clock rate first to make sure the
++	 * secondary mux is not sourcing off of QSB. The rate is then set to
++	 * two different rates to force a HFPLL reinit under all
++	 * circumstances.
++	 */
++	cur_rate = clk_get_rate(l2_pri_mux_clk);
++	aux_rate = 384000000;
++	if (cur_rate == 1) {
++		pr_info("L2 @ QSB rate. Forcing new rate.\n");
++		cur_rate = aux_rate;
++	}
++	clk_set_rate(l2_pri_mux_clk, aux_rate);
++	clk_set_rate(l2_pri_mux_clk, 2);
++	clk_set_rate(l2_pri_mux_clk, cur_rate);
++	pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000);
++	for_each_possible_cpu(cpu) {
++		clk = clks[cpu];
++		cur_rate = clk_get_rate(clk);
++		if (cur_rate == 1) {
++			pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu);
++			cur_rate = aux_rate;
++		}
++
++		clk_set_rate(clk, aux_rate);
++		clk_set_rate(clk, 2);
++		clk_set_rate(clk, cur_rate);
++		pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000);
++	}
++
++	of_clk_add_provider(dev->of_node, krait_of_get, clks);
++
++	return 0;
++}
++
++static struct platform_driver krait_cc_driver = {
++	.probe = krait_cc_probe,
++	.driver = {
++		.name = "krait-cc",
++		.of_match_table = krait_cc_match_table,
++	},
++};
++module_platform_driver(krait_cc_driver);
++
++MODULE_DESCRIPTION("Krait CPU Clock Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:krait-cc");
diff --git a/target/linux/ipq806x/patches-4.14/0044-clk-Add-safe-switch-hook.patch b/target/linux/ipq806x/patches-4.14/0044-clk-Add-safe-switch-hook.patch
new file mode 100644
index 0000000..b2468a9
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0044-clk-Add-safe-switch-hook.patch
@@ -0,0 +1,160 @@ 
+From patchwork Fri Dec  8 09:42:28 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,10/12] clk: qcom: Add safe switch hook for krait mux clocks
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102057
+Message-Id: <1512726150-7204-11-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:28 +0530
+
+When the Hfplls are reprogrammed during the rate change,
+the primary muxes which are sourced from the same hfpll
+for higher frequencies, needs to be switched to the 'safe
+secondary mux' as the parent for that small window. This
+is done by registering a clk notifier for the muxes and
+switching to the safe parent in the PRE_RATE_CHANGE notifier
+and back to the original parent in the POST_RATE_CHANGE notifier.
+
+Signed-off-by: Sricharan R <sricharan@codeaurora.org>
+---
+ drivers/clk/qcom/clk-krait.c |  2 ++
+ drivers/clk/qcom/clk-krait.h |  3 +++
+ drivers/clk/qcom/krait-cc.c  | 56 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 61 insertions(+)
+
+--- a/drivers/clk/qcom/clk-krait.c
++++ b/drivers/clk/qcom/clk-krait.c
+@@ -60,6 +60,8 @@ static int krait_mux_set_parent(struct c
+	if (__clk_is_enabled(hw->clk))
+		__krait_mux_set_sel(mux, sel);
+
++	mux->reparent = true;
++
+	return 0;
+ }
+
+--- a/drivers/clk/qcom/clk-krait.h
++++ b/drivers/clk/qcom/clk-krait.h
+@@ -23,6 +23,9 @@ struct krait_mux_clk {
+	u32		shift;
+	u32		en_mask;
+	bool		lpl;
++	u8		safe_sel;
++	u8		old_index;
++	bool		reparent;
+
+	struct clk_hw	hw;
+	struct notifier_block   clk_nb;
+--- a/drivers/clk/qcom/krait-cc.c
++++ b/drivers/clk/qcom/krait-cc.c
+@@ -35,6 +35,49 @@ static unsigned int pri_mux_map[] = {
+	0,
+ };
+
++/*
++ * Notifier function for switching the muxes to safe parent
++ * while the hfpll is getting reprogrammed.
++ */
++static int krait_notifier_cb(struct notifier_block *nb,
++			     unsigned long event,
++			     void *data)
++{
++	int ret = 0;
++	struct krait_mux_clk *mux = container_of(nb, struct krait_mux_clk,
++						 clk_nb);
++	/* Switch to safe parent */
++	if (event == PRE_RATE_CHANGE) {
++		mux->old_index = krait_mux_clk_ops.get_parent(&mux->hw);
++		ret = krait_mux_clk_ops.set_parent(&mux->hw, mux->safe_sel);
++		mux->reparent = false;
++	/*
++	 * By the time POST_RATE_CHANGE notifier is called,
++	 * clk framework itself would have changed the parent for the new rate.
++	 * Only otherwise, put back to the old parent.
++	 */
++	} else if (event == POST_RATE_CHANGE) {
++		if (!mux->reparent)
++			ret = krait_mux_clk_ops.set_parent(&mux->hw,
++							   mux->old_index);
++	}
++
++	return notifier_from_errno(ret);
++}
++
++static int krait_notifier_register(struct device *dev, struct clk *clk,
++				   struct krait_mux_clk *mux)
++{
++	int ret = 0;
++
++	mux->clk_nb.notifier_call = krait_notifier_cb;
++	ret = clk_notifier_register(clk, &mux->clk_nb);
++	if (ret)
++		dev_err(dev, "failed to register clock notifier: %d\n", ret);
++
++	return ret;
++}
++
+ static int
+ krait_add_div(struct device *dev, int id, const char *s, unsigned int offset)
+ {
+@@ -79,6 +122,7 @@ static int
+ krait_add_sec_mux(struct device *dev, int id, const char *s,
+		  unsigned int offset, bool unique_aux)
+ {
++	int ret;
+	struct krait_mux_clk *mux;
+	static const char *sec_mux_list[] = {
+		"acpu_aux",
+@@ -102,6 +146,7 @@ krait_add_sec_mux(struct device *dev, in
+	mux->shift = 2;
+	mux->parent_map = sec_mux_map;
+	mux->hw.init = &init;
++	mux->safe_sel = 0;
+
+	init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
+	if (!init.name)
+@@ -117,6 +162,11 @@ krait_add_sec_mux(struct device *dev, in
+
+	clk = devm_clk_register(dev, &mux->hw);
+
++	ret = krait_notifier_register(dev, clk, mux);
++	if (ret)
++		goto unique_aux;
++
++unique_aux:
+	if (unique_aux)
+		kfree(sec_mux_list[0]);
+ err_aux:
+@@ -128,6 +178,7 @@ static struct clk *
+ krait_add_pri_mux(struct device *dev, int id, const char *s,
+		  unsigned int offset)
+ {
++	int ret;
+	struct krait_mux_clk *mux;
+	const char *p_names[3];
+	struct clk_init_data init = {
+@@ -148,6 +199,7 @@ krait_add_pri_mux(struct device *dev, in
+	mux->lpl = id >= 0;
+	mux->parent_map = pri_mux_map;
+	mux->hw.init = &init;
++	mux->safe_sel = 2;
+
+	init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
+	if (!init.name)
+@@ -173,6 +225,10 @@ krait_add_pri_mux(struct device *dev, in
+
+	clk = devm_clk_register(dev, &mux->hw);
+
++	ret = krait_notifier_register(dev, clk, mux);
++	if (ret)
++		goto err_p3;
++err_p3:
+	kfree(p_names[2]);
+ err_p2:
+	kfree(p_names[1]);
diff --git a/target/linux/ipq806x/patches-4.14/0045-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch b/target/linux/ipq806x/patches-4.14/0045-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch
new file mode 100644
index 0000000..b894173
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0045-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch
@@ -0,0 +1,307 @@ 
+From patchwork Fri Dec  8 09:42:29 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,11/12] cpufreq: Add module to register cpufreq on Krait CPUs
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102075
+Message-Id: <1512726150-7204-12-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:29 +0530
+
+From: Stephen Boyd <sboyd@codeaurora.org>
+
+Register a cpufreq-generic device whenever we detect that a
+"qcom,krait" compatible CPU is present in DT.
+
+Cc: <devicetree@vger.kernel.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+---
+ .../devicetree/bindings/arm/msm/qcom,pvs.txt       |  38 ++++
+ drivers/cpufreq/Kconfig.arm                        |   9 +
+ drivers/cpufreq/Makefile                           |   1 +
+ drivers/cpufreq/qcom-cpufreq.c                     | 204 +++++++++++++++++++++
+ 4 files changed, 252 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt
+ create mode 100644 drivers/cpufreq/qcom-cpufreq.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt
+@@ -0,0 +1,38 @@
++Qualcomm Process Voltage Scaling Tables
++
++The node name is required to be "qcom,pvs". There shall only be one
++such node present in the root of the tree.
++
++PROPERTIES
++
++- qcom,pvs-format-a or qcom,pvs-format-b:
++	Usage: required
++	Value type: <empty>
++	Definition: Indicates the format of qcom,speedX-pvsY-bin-vZ properties.
++		    If qcom,pvs-format-a is used the table is two columns
++		    (frequency and voltage in that order). If qcom,pvs-format-b 		    is used the table is three columns (frequency, voltage,
++		    and current in that order).
++
++- qcom,speedX-pvsY-bin-vZ:
++	Usage: required
++	Value type: <prop-encoded-array>
++	Definition: The PVS table corresponding to the speed bin X, pvs bin Y,
++		    and version Z.
++Example:
++
++	qcom,pvs {
++		qcom,pvs-format-a;
++		qcom,speed0-pvs0-bin-v0 =
++			<  384000000  950000 >,
++			<  486000000  975000 >,
++			<  594000000 1000000 >,
++			<  702000000 1025000 >,
++			<  810000000 1075000 >,
++			<  918000000 1100000 >,
++			< 1026000000 1125000 >,
++			< 1134000000 1175000 >,
++			< 1242000000 1200000 >,
++			< 1350000000 1225000 >,
++			< 1458000000 1237500 >,
++			< 1512000000 1250000 >;
++	};
+--- a/drivers/cpufreq/Kconfig.arm
++++ b/drivers/cpufreq/Kconfig.arm
+@@ -100,6 +100,15 @@ config ARM_OMAP2PLUS_CPUFREQ
+	depends on ARCH_OMAP2PLUS
+	default ARCH_OMAP2PLUS
+
++config ARM_QCOM_CPUFREQ
++	tristate "Qualcomm based"
++	depends on ARCH_QCOM
++	select PM_OPP
++	help
++	  This adds the CPUFreq driver for Qualcomm SoC based boards.
++
++	  If in doubt, say N.
++
+ config ARM_S3C_CPUFREQ
+	bool
+	help
+--- a/drivers/cpufreq/Makefile
++++ b/drivers/cpufreq/Makefile
+@@ -62,6 +62,7 @@ obj-$(CONFIG_ARM_MT8173_CPUFREQ)	+= mt81
+ obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)	+= omap-cpufreq.o
+ obj-$(CONFIG_ARM_PXA2xx_CPUFREQ)	+= pxa2xx-cpufreq.o
+ obj-$(CONFIG_PXA3xx)			+= pxa3xx-cpufreq.o
++obj-$(CONFIG_ARM_QCOM_CPUFREQ)		+= qcom-cpufreq.o
+ obj-$(CONFIG_ARM_S3C24XX_CPUFREQ)	+= s3c24xx-cpufreq.o
+ obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o
+ obj-$(CONFIG_ARM_S3C2410_CPUFREQ)	+= s3c2410-cpufreq.o
+--- /dev/null
++++ b/drivers/cpufreq/qcom-cpufreq.c
+@@ -0,0 +1,204 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/cpu.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/pm_opp.h>
++#include <linux/slab.h>
++#include "cpufreq-dt.h"
++
++static void __init get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver)
++{
++	void __iomem *base;
++	u32 pte_efuse;
++
++	*speed = *pvs = *pvs_ver = 0;
++
++	base = ioremap(0x007000c0, 4);
++	if (!base) {
++		pr_warn("Unable to read efuse data. Defaulting to 0!\n");
++		return;
++	}
++
++	pte_efuse = readl_relaxed(base);
++	iounmap(base);
++
++	*speed = pte_efuse & 0xf;
++	if (*speed == 0xf)
++		*speed = (pte_efuse >> 4) & 0xf;
++
++	if (*speed == 0xf) {
++		*speed = 0;
++		pr_warn("Speed bin: Defaulting to %d\n", *speed);
++	} else {
++		pr_info("Speed bin: %d\n", *speed);
++	}
++
++	*pvs = (pte_efuse >> 10) & 0x7;
++	if (*pvs == 0x7)
++		*pvs = (pte_efuse >> 13) & 0x7;
++
++	if (*pvs == 0x7) {
++		*pvs = 0;
++		pr_warn("PVS bin: Defaulting to %d\n", *pvs);
++	} else {
++		pr_info("PVS bin: %d\n", *pvs);
++	}
++}
++
++static void __init get_krait_bin_format_b(int *speed, int *pvs, int *pvs_ver)
++{
++	u32 pte_efuse, redundant_sel;
++	void __iomem *base;
++
++	*speed = 0;
++	*pvs = 0;
++	*pvs_ver = 0;
++
++	base = ioremap(0xfc4b80b0, 8);
++	if (!base) {
++		pr_warn("Unable to read efuse data. Defaulting to 0!\n");
++		return;
++	}
++
++	pte_efuse = readl_relaxed(base);
++	redundant_sel = (pte_efuse >> 24) & 0x7;
++	*speed = pte_efuse & 0x7;
++	/* 4 bits of PVS are in efuse register bits 31, 8-6. */
++	*pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
++	*pvs_ver = (pte_efuse >> 4) & 0x3;
++
++	switch (redundant_sel) {
++	case 1:
++		*speed = (pte_efuse >> 27) & 0xf;
++		break;
++	case 2:
++		*pvs = (pte_efuse >> 27) & 0xf;
++		break;
++	}
++
++	/* Check SPEED_BIN_BLOW_STATUS */
++	if (pte_efuse & BIT(3)) {
++		pr_info("Speed bin: %d\n", *speed);
++	} else {
++		pr_warn("Speed bin not set. Defaulting to 0!\n");
++		*speed = 0;
++	}
++
++	/* Check PVS_BLOW_STATUS */
++	pte_efuse = readl_relaxed(base + 0x4) & BIT(21);
++	if (pte_efuse) {
++		pr_info("PVS bin: %d\n", *pvs);
++	} else {
++		pr_warn("PVS bin not set. Defaulting to 0!\n");
++		*pvs = 0;
++	}
++
++	pr_info("PVS version: %d\n", *pvs_ver);
++	iounmap(base);
++}
++
++static int __init qcom_cpufreq_populate_opps(void)
++{
++	int len, rows, cols, i, k, speed, pvs, pvs_ver;
++	char table_name[] = "qcom,speedXX-pvsXX-bin-vXX";
++	struct device_node *np;
++	struct device *dev;
++	int cpu = 0;
++
++	np = of_find_node_by_name(NULL, "qcom,pvs");
++	if (!np)
++		return -ENODEV;
++
++	if (of_property_read_bool(np, "qcom,pvs-format-a")) {
++		get_krait_bin_format_a(&speed, &pvs, &pvs_ver);
++		cols = 2;
++	} else if (of_property_read_bool(np, "qcom,pvs-format-b")) {
++		get_krait_bin_format_b(&speed, &pvs, &pvs_ver);
++		cols = 3;
++	} else {
++		return -ENODEV;
++	}
++
++	snprintf(table_name, sizeof(table_name),
++		 "qcom,speed%d-pvs%d-bin-v%d", speed, pvs, pvs_ver);
++
++	if (!of_find_property(np, table_name, &len))
++		return -EINVAL;
++
++	len /= sizeof(u32);
++	if (len % cols || len == 0)
++		return -EINVAL;
++
++	rows = len / cols;
++
++	for (i = 0, k = 0; i < rows; i++) {
++		u32 freq, volt;
++
++		of_property_read_u32_index(np, table_name, k++, &freq);
++		of_property_read_u32_index(np, table_name, k++, &volt);
++		while (k % cols)
++			k++; /* Skip uA entries if present */
++		for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
++			dev = get_cpu_device(cpu);
++			if (!dev)
++				return -ENODEV;
++			if (dev_pm_opp_add(dev, freq, volt))
++				pr_warn("failed to add OPP %u\n", freq);
++		}
++	}
++
++	return 0;
++}
++
++static int __init qcom_cpufreq_driver_init(void)
++{
++	struct cpufreq_dt_platform_data pdata = { .independent_clocks = true };
++	struct platform_device_info devinfo = {
++		.name = "cpufreq-dt",
++		.data = &pdata,
++		.size_data = sizeof(pdata),
++	};
++	struct device *cpu_dev;
++	struct device_node *np;
++	int ret;
++
++	cpu_dev = get_cpu_device(0);
++	if (!cpu_dev)
++		return -ENODEV;
++
++	np = of_node_get(cpu_dev->of_node);
++	if (!np)
++		return -ENOENT;
++
++	if (!of_device_is_compatible(np, "qcom,krait")) {
++		of_node_put(np);
++		return -ENODEV;
++	}
++	of_node_put(np);
++
++	ret = qcom_cpufreq_populate_opps();
++	if (ret)
++		return ret;
++
++	return PTR_ERR_OR_ZERO(platform_device_register_full(&devinfo));
++}
++module_init(qcom_cpufreq_driver_init);
++
++MODULE_DESCRIPTION("Qualcomm CPUfreq driver");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ipq806x/patches-4.14/0046-cpufreq-qcom-independent-core-clocks.patch b/target/linux/ipq806x/patches-4.14/0046-cpufreq-qcom-independent-core-clocks.patch
new file mode 100644
index 0000000..d7211e1
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0046-cpufreq-qcom-independent-core-clocks.patch
@@ -0,0 +1,65 @@ 
+From patchwork Fri Dec  8 09:42:30 2017
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v4,12/12] cpufreq: dt: Reintroduce independent_clocks platform data
+From: Sricharan R <sricharan@codeaurora.org>
+X-Patchwork-Id: 10102073
+Message-Id: <1512726150-7204-13-git-send-email-sricharan@codeaurora.org>
+To: mturquette@baylibre.com, sboyd@codeaurora.org,
+ devicetree@vger.kernel.org, linux-pm@vger.kernel.org,
+ linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
+ viresh.kumar@linaro.org, linux-arm-kernel@lists.infradead.org
+Cc: sricharan@codeaurora.org
+Date: Fri,  8 Dec 2017 15:12:30 +0530
+
+The Platform data was removed earlier by,
+'commit eb96924acddc ("cpufreq: dt: Kill platform-data")'
+since there were no users at that time.
+Now this is required when the each of the cpu clocks
+can be scaled independently, which is the case
+for krait cores. So reintroduce it.
+
+Signed-off-by: Sricharan R <sricharan@codeaurora.org>
+---
+ drivers/cpufreq/cpufreq-dt.c | 7 ++++++-
+ drivers/cpufreq/cpufreq-dt.h | 6 ++++++
+ 2 files changed, 12 insertions(+), 1 deletion(-)
+
+--- a/drivers/cpufreq/cpufreq-dt.c
++++ b/drivers/cpufreq/cpufreq-dt.c
+@@ -220,7 +220,10 @@ static int cpufreq_init(struct cpufreq_p
+	}
+
+	if (fallback) {
+-		cpumask_setall(policy->cpus);
++		struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data();
++
++		if (!pd || !pd->independent_clocks)
++			cpumask_setall(policy->cpus);
+
+		/*
+		 * OPP tables are initialized only for policy->cpu, do it for
+@@ -372,6 +375,8 @@ static int dt_cpufreq_probe(struct platf
+	if (data && data->have_governor_per_policy)
+		dt_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY;
+
++	dt_cpufreq_driver.driver_data = data;
++
+	ret = cpufreq_register_driver(&dt_cpufreq_driver);
+	if (ret)
+		dev_err(&pdev->dev, "failed register driver: %d\n", ret);
+--- a/drivers/cpufreq/cpufreq-dt.h
++++ b/drivers/cpufreq/cpufreq-dt.h
+@@ -13,6 +13,12 @@
+ #include <linux/types.h>
+
+ struct cpufreq_dt_platform_data {
++	/*
++	 * True when each CPU has its own clock to control its
++	 * frequency, false when all CPUs are controlled by a single
++	 * clock.
++	 */
++	bool independent_clocks;
+	bool have_governor_per_policy;
+ };
diff --git a/target/linux/ipq806x/patches-4.14/0047-mtd-nand-Create-a-BBT-flag-to-access-bad-block-marke.patch b/target/linux/ipq806x/patches-4.14/0047-mtd-nand-Create-a-BBT-flag-to-access-bad-block-marke.patch
new file mode 100644
index 0000000..4c271d7
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0047-mtd-nand-Create-a-BBT-flag-to-access-bad-block-marke.patch
@@ -0,0 +1,72 @@ 
+From c7c6a0f50f9ac3620c611ce06ba1f9fafea0444e Mon Sep 17 00:00:00 2001
+From: Archit Taneja <architt@codeaurora.org>
+Date: Mon, 3 Aug 2015 10:38:14 +0530
+Subject: [PATCH 47/69] mtd: nand: Create a BBT flag to access bad block
+ markers in raw mode
+
+Some controllers can access the factory bad block marker from OOB only
+when they read it in raw mode. When ECC is enabled, these controllers
+discard reading/writing bad block markers, preventing access to them
+altogether.
+
+The bbt driver assumes MTD_OPS_PLACE_OOB when scanning for bad blocks.
+This results in the nand driver's ecc->read_oob() op to be called, which
+works with ECC enabled.
+
+Create a new BBT option flag that tells nand_bbt to force the mode to
+MTD_OPS_RAW. This would result in the correct op being called for the
+underlying nand controller driver.
+
+Reviewed-by: Andy Gross <agross@codeaurora.org>
+Signed-off-by: Archit Taneja <architt@codeaurora.org>
+---
+ drivers/mtd/nand/nand_base.c | 6 +++++-
+ drivers/mtd/nand/nand_bbt.c  | 6 +++++-
+ include/linux/mtd/bbm.h      | 6 ++++++
+ 3 files changed, 16 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -481,7 +481,11 @@ static int nand_default_block_markbad(st
+	} else {
+		ops.len = ops.ooblen = 1;
+	}
+-	ops.mode = MTD_OPS_PLACE_OOB;
++
++	if (unlikely(chip->bbt_options & NAND_BBT_ACCESS_BBM_RAW))
++		ops.mode = MTD_OPS_RAW;
++	else
++		ops.mode = MTD_OPS_PLACE_OOB;
+
+	/* Write to first/last page(s) if necessary */
+	if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+--- a/drivers/mtd/nand/nand_bbt.c
++++ b/drivers/mtd/nand/nand_bbt.c
+@@ -420,7 +420,11 @@ static int scan_block_fast(struct mtd_in
+	ops.oobbuf = buf;
+	ops.ooboffs = 0;
+	ops.datbuf = NULL;
+-	ops.mode = MTD_OPS_PLACE_OOB;
++
++	if (unlikely(bd->options & NAND_BBT_ACCESS_BBM_RAW))
++		ops.mode = MTD_OPS_RAW;
++	else
++		ops.mode = MTD_OPS_PLACE_OOB;
+
+	for (j = 0; j < numpages; j++) {
+		/*
+--- a/include/linux/mtd/bbm.h
++++ b/include/linux/mtd/bbm.h
+@@ -116,6 +116,12 @@ struct nand_bbt_descr {
+ #define NAND_BBT_NO_OOB_BBM	0x00080000
+
+ /*
++ * Force MTD_OPS_RAW mode when trying to access bad block markes from OOB. To
++ * be used by controllers which can access BBM only when ECC is disabled, i.e,
++ * when in RAW access mode
++ */
++#define NAND_BBT_ACCESS_BBM_RAW        0x00100000
++/*
+  * Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr
+  * was allocated dynamicaly and must be freed in nand_release(). Has no meaning
+  * in nand_chip.bbt_options.
diff --git a/target/linux/ipq806x/patches-4.14/0048-PM-OPP-HACK-Allow-to-set-regulator-without-opp_list.patch b/target/linux/ipq806x/patches-4.14/0048-PM-OPP-HACK-Allow-to-set-regulator-without-opp_list.patch
new file mode 100644
index 0000000..be39ad2
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0048-PM-OPP-HACK-Allow-to-set-regulator-without-opp_list.patch
@@ -0,0 +1,26 @@ 
+From 5c294df1715d673f94f3b0a6e1ea3a426ca35e6e Mon Sep 17 00:00:00 2001
+From: Georgi Djakov <georgi.djakov@linaro.org>
+Date: Thu, 28 Apr 2016 16:20:12 +0300
+Subject: [PATCH 48/69] PM / OPP: HACK: Allow to set regulator without opp_list
+
+Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
+---
+ drivers/base/power/opp/core.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/base/power/opp/core.c
++++ b/drivers/base/power/opp/core.c
+@@ -1277,11 +1277,13 @@
+	if (!opp_table)
+		return ERR_PTR(-ENOMEM);
+
++#if 0
+	/* This should be called before OPPs are initialized */
+	if (WARN_ON(!list_empty(&opp_table->opp_list))) {
+		ret = -EBUSY;
+		goto err;
+	}
++#endif
+
+	/* Already have regulators set */
+	if (opp_table->regulators) {
diff --git a/target/linux/ipq806x/patches-4.14/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch b/target/linux/ipq806x/patches-4.14/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch
new file mode 100644
index 0000000..2ab46e1
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0049-PM-OPP-Support-adjusting-OPP-voltages-at-runtime.patch
@@ -0,0 +1,147 @@ 
+From c949f08cf20fe82971fbdb4015daa38210da492e Mon Sep 17 00:00:00 2001
+From: Stephen Boyd <sboyd@codeaurora.org>
+Date: Fri, 18 Sep 2015 17:52:06 -0700
+Subject: [PATCH 49/69] PM / OPP: Support adjusting OPP voltages at runtime
+
+On some SoCs the Adaptive Voltage Scaling (AVS) technique is
+employed to optimize the operating voltage of a device. At a
+given frequency, the hardware monitors dynamic factors and either
+makes a suggestion for how much to adjust a voltage for the
+current frequency, or it automatically adjusts the voltage
+without software intervention. Add an API to the OPP library for
+the former case, so that AVS type devices can update the voltages
+for an OPP when the hardware determines the voltage should
+change. The assumption is that drivers like CPUfreq or devfreq
+will register for the OPP notifiers and adjust the voltage
+according to suggestions that AVS makes.
+
+Cc: Nishanth Menon <nm@ti.com>
+Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
+Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
+---
+ drivers/base/power/opp/core.c | 77 +++++++++++++++++++++++++++++++++++++++++++
+ include/linux/pm_opp.h        | 11 +++++++
+ 2 files changed, 88 insertions(+)
+
+--- a/drivers/base/power/opp/core.c
++++ b/drivers/base/power/opp/core.c
+@@ -1605,6 +1605,83 @@ unlock:
+ }
+
+ /**
++ * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP
++ * @dev:		device for which we do this operation
++ * @freq:		OPP frequency to adjust voltage of
++ * @u_volt:		new OPP voltage
++ *
++ * Change the voltage of an OPP with an RCU operation.
++ *
++ * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
++ * copy operation, returns 0 if no modifcation was done OR modification was
++ * successful.
++ *
++ * Locking: The internal device_opp and opp structures are RCU protected.
++ * Hence this function internally uses RCU updater strategy with mutex locks to
++ * keep the integrity of the internal data structures. Callers should ensure
++ * that this function is *NOT* called under RCU protection or in contexts where
++ * mutex locking or synchronize_rcu() blocking calls cannot be used.
++ */
++int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
++			      unsigned long u_volt)
++{
++	struct opp_table *opp_table;
++	struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV);
++	int r = 0;
++
++	/* keep the node allocated */
++	new_opp = kmalloc(sizeof(*new_opp), GFP_KERNEL);
++	if (!new_opp)
++		return -ENOMEM;
++
++	mutex_lock(&opp_table_lock);
++
++	/* Find the opp_table */
++	opp_table = _find_opp_table(dev);
++	if (IS_ERR(opp_table)) {
++		r = PTR_ERR(opp_table);
++		dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
++		goto unlock;
++	}
++
++	/* Do we have the frequency? */
++	list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
++		if (tmp_opp->rate == freq) {
++			opp = tmp_opp;
++			break;
++		}
++	}
++	if (IS_ERR(opp)) {
++		r = PTR_ERR(opp);
++		goto unlock;
++	}
++
++	/* Is update really needed? */
++	if (opp->supplies[0].u_volt == u_volt)
++		goto unlock;
++	/* copy the old data over */
++	*new_opp = *opp;
++
++	/* plug in new node */
++	new_opp->supplies[0].u_volt = u_volt;
++
++	list_replace(&opp->node, &new_opp->node);
++	mutex_unlock(&opp_table_lock);
++	kfree(opp);
++
++	/* Notify the change of the OPP */
++	blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE,
++				 new_opp);
++
++	return 0;
++
++unlock:
++	mutex_unlock(&opp_table_lock);
++	kfree(new_opp);
++	return r;
++}
++
++/**
+  * dev_pm_opp_enable() - Enable a specific OPP
+  * @dev:	device for which we do this operation
+  * @freq:	OPP frequency to enable
+--- a/include/linux/pm_opp.h
++++ b/include/linux/pm_opp.h
+@@ -25,6 +25,7 @@ struct opp_table;
+
+ enum dev_pm_opp_event {
+	OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
++	OPP_EVENT_ADJUST_VOLTAGE,
+ };
+
+ /**
+@@ -108,6 +109,9 @@ int dev_pm_opp_add(struct device *dev, u
+		   unsigned long u_volt);
+ void dev_pm_opp_remove(struct device *dev, unsigned long freq);
+
++int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
++			      unsigned long u_volt);
++
+ int dev_pm_opp_enable(struct device *dev, unsigned long freq);
+
+ int dev_pm_opp_disable(struct device *dev, unsigned long freq);
+@@ -208,6 +212,13 @@ static inline void dev_pm_opp_remove(str
+ {
+ }
+
++static inline int
++dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
++			  unsigned long u_volt)
++{
++	return 0;
++}
++
+ static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq)
+ {
+	return 0;
diff --git a/target/linux/ipq806x/patches-4.14/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch b/target/linux/ipq806x/patches-4.14/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch
new file mode 100644
index 0000000..f0705ba
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0051-PM-OPP-Add-a-helper-to-get-an-opp-regulator-for-devi.patch
@@ -0,0 +1,51 @@ 
+From d06ca5e7a3cf726f5be5ffd96e93ccd798b8c09a Mon Sep 17 00:00:00 2001
+From: Georgi Djakov <georgi.djakov@linaro.org>
+Date: Thu, 12 May 2016 14:41:33 +0300
+Subject: [PATCH 51/69] PM / OPP: Add a helper to get an opp regulator for
+ device
+
+Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
+---
+ drivers/base/power/opp/core.c | 21 +++++++++++++++++++++
+ include/linux/pm_opp.h        |  1 +
+ 2 files changed, 22 insertions(+)
+
+--- a/drivers/base/power/opp/core.c
++++ b/drivers/base/power/opp/core.c
+@@ -126,6 +126,27 @@ unsigned long dev_pm_opp_get_freq(struct
+ }
+ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
+
++struct regulator *dev_pm_opp_get_regulator(struct device *dev)
++{
++	struct opp_table *opp_table;
++	struct regulator *reg;
++
++	rcu_read_lock();
++
++	opp_table = _find_opp_table(dev);
++	if (IS_ERR(opp_table)) {
++		rcu_read_unlock();
++		return ERR_CAST(opp_table);
++	}
++
++	reg = opp_table->regulators[0];
++
++	rcu_read_unlock();
++
++	return reg;
++}
++EXPORT_SYMBOL_GPL(dev_pm_opp_get_regulator);
++
+ /**
+  * dev_pm_opp_is_turbo() - Returns if opp is turbo OPP or not
+  * @opp: opp for which turbo mode is being verified
+--- a/include/linux/pm_opp.h
++++ b/include/linux/pm_opp.h
+@@ -85,6 +85,7 @@ enum dev_pm_opp_event {
+ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
+
+ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
++struct regulator *dev_pm_opp_get_regulator(struct device *dev);
+
+ bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp);
diff --git a/target/linux/ipq806x/patches-4.14/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch b/target/linux/ipq806x/patches-4.14/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch
new file mode 100644
index 0000000..711e14c
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0052-PM-OPP-Update-the-voltage-tolerance-when-adjusting-t.patch
@@ -0,0 +1,38 @@ 
+From 4533c285c2aedce6d4434d7b877066de3b1ecb33 Mon Sep 17 00:00:00 2001
+From: Georgi Djakov <georgi.djakov@linaro.org>
+Date: Thu, 25 Aug 2016 18:43:35 +0300
+Subject: [PATCH 52/69] PM / OPP: Update the voltage tolerance when adjusting
+ the OPP
+
+When the voltage is adjusted, the voltage tolerance is not updated.
+This can lead to situations where the voltage min value is greater
+than the voltage max value. The final result is triggering a BUG()
+in the regulator core.
+Fix this by updating the voltage tolerance values too.
+
+Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
+---
+ drivers/base/power/opp/core.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/base/power/opp/core.c
++++ b/drivers/base/power/opp/core.c
+@@ -1649,6 +1649,7 @@ int dev_pm_opp_adjust_voltage(struct dev
+	struct opp_table *opp_table;
+	struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV);
+	int r = 0;
++	unsigned long tol;
+
+	/* keep the node allocated */
+	new_opp = kmalloc(sizeof(*new_opp), GFP_KERNEL);
+@@ -1685,6 +1686,10 @@ int dev_pm_opp_adjust_voltage(struct dev
+
+	/* plug in new node */
+	new_opp->supplies[0].u_volt = u_volt;
++	tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
++	new_opp->supplies[0].u_volt = u_volt;
++	new_opp->supplies[0].u_volt_min = u_volt - tol;
++	new_opp->supplies[0].u_volt_max = u_volt + tol;
+
+	list_replace(&opp->node, &new_opp->node);
+	mutex_unlock(&opp_table_lock);
diff --git a/target/linux/ipq806x/patches-4.14/0053-regulator-add-smb208-support.patch b/target/linux/ipq806x/patches-4.14/0053-regulator-add-smb208-support.patch
new file mode 100644
index 0000000..dd4abb1
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0053-regulator-add-smb208-support.patch
@@ -0,0 +1,55 @@ 
+From ef10381ca4d01848ebedb4afb2c78feb8052f103 Mon Sep 17 00:00:00 2001
+From: Adrian Panella <ianchi74@outlook.com>
+Date: Thu, 9 Mar 2017 08:26:54 +0100
+Subject: [PATCH 53/69] regulator: add smb208 support
+
+Signed-off-by: Adrian Panella <ianchi74@outlook.com>
+---
+ Documentation/devicetree/bindings/mfd/qcom-rpm.txt | 4 ++++
+ drivers/regulator/qcom_rpm-regulator.c             | 9 +++++++++
+ 2 files changed, 13 insertions(+)
+
+--- a/Documentation/devicetree/bindings/mfd/qcom-rpm.txt
++++ b/Documentation/devicetree/bindings/mfd/qcom-rpm.txt
+@@ -61,6 +61,7 @@ Regulator nodes are identified by their
+		    "qcom,rpm-pm8901-regulators"
+		    "qcom,rpm-pm8921-regulators"
+		    "qcom,rpm-pm8018-regulators"
++		    "qcom,rpm-smb208-regulators"
+
+ - vdd_l0_l1_lvs-supply:
+ - vdd_l2_l11_l12-supply:
+@@ -171,6 +172,9 @@ pm8018:
+	s1, s2, s3, s4, s5, , l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11,
+	l12, l14, lvs1
+
++smb208:
++	s1a, s1b, s2a, s2b
++
+ The content of each sub-node is defined by the standard binding for regulators -
+ see regulator.txt - with additional custom properties described below:
+
+--- a/drivers/regulator/qcom_rpm-regulator.c
++++ b/drivers/regulator/qcom_rpm-regulator.c
+@@ -933,12 +933,21 @@ static const struct rpm_regulator_data r
+	{ }
+ };
+
++static const struct rpm_regulator_data rpm_smb208_regulators[] = {
++	{ "s1a",  QCOM_RPM_SMB208_S1a, &smb208_smps, "vin_s1a" },
++	{ "s1b",  QCOM_RPM_SMB208_S1b, &smb208_smps, "vin_s1b" },
++	{ "s2a",  QCOM_RPM_SMB208_S2a, &smb208_smps, "vin_s2a" },
++	{ "s2b",  QCOM_RPM_SMB208_S2b, &smb208_smps, "vin_s2b" },
++	{ }
++};
++
+ static const struct of_device_id rpm_of_match[] = {
+	{ .compatible = "qcom,rpm-pm8018-regulators",
+		.data = &rpm_pm8018_regulators },
+	{ .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators },
+	{ .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators },
+	{ .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators },
++	{ .compatible = "qcom,rpm-smb208-regulators", .data = &rpm_smb208_regulators },
+	{ }
+ };
+ MODULE_DEVICE_TABLE(of, rpm_of_match);
diff --git a/target/linux/ipq806x/patches-4.14/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch b/target/linux/ipq806x/patches-4.14/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch
new file mode 100644
index 0000000..47c64ec
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0054-cpufreq-dt-Handle-OPP-voltage-adjust-events.patch
@@ -0,0 +1,131 @@ 
+From 10577f74c35bd395951d1b2382c8d821089b5745 Mon Sep 17 00:00:00 2001
+From: Stephen Boyd <sboyd@codeaurora.org>
+Date: Fri, 18 Sep 2015 17:52:08 -0700
+Subject: [PATCH 54/69] cpufreq-dt: Handle OPP voltage adjust events
+
+On some SoCs the Adaptive Voltage Scaling (AVS) technique is
+employed to optimize the operating voltage of a device. At a
+given frequency, the hardware monitors dynamic factors and either
+makes a suggestion for how much to adjust a voltage for the
+current frequency, or it automatically adjusts the voltage
+without software intervention.
+
+In the former case, an AVS driver will call
+dev_pm_opp_modify_voltage() and update the voltage for the
+particular OPP the CPUs are using. Add an OPP notifier to
+cpufreq-dt so that we can adjust the voltage of the CPU when AVS
+updates the OPP.
+
+Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
+Acked-by: Viresh Kumar <viresh.kumar@linaro.org>
+Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
+---
+ drivers/cpufreq/cpufreq-dt.c | 68 ++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 65 insertions(+), 3 deletions(-)
+
+--- a/drivers/cpufreq/cpufreq-dt.c
++++ b/drivers/cpufreq/cpufreq-dt.c
+@@ -32,6 +32,9 @@ struct private_data {
+	struct device *cpu_dev;
+	struct thermal_cooling_device *cdev;
+	const char *reg_name;
++	struct notifier_block opp_nb;
++	struct mutex lock;
++	unsigned long opp_freq;
+ };
+
+ static struct freq_attr *cpufreq_dt_attr[] = {
+@@ -43,9 +46,16 @@ static struct freq_attr *cpufreq_dt_attr
+ static int set_target(struct cpufreq_policy *policy, unsigned int index)
+ {
+	struct private_data *priv = policy->driver_data;
++	int ret;
++	unsigned long target_freq = policy->freq_table[index].frequency * 1000;
++
++	mutex_lock(&priv->lock);
++	ret = dev_pm_opp_set_rate(priv->cpu_dev, target_freq);
++	if (!ret)
++		priv->opp_freq = target_freq;
++	mutex_unlock(&priv->lock);
+
+-	return dev_pm_opp_set_rate(priv->cpu_dev,
+-				   policy->freq_table[index].frequency * 1000);
++	return ret;
+ }
+
+ /*
+@@ -86,6 +96,39 @@ node_put:
+	return name;
+ }
+
++static int opp_notifier(struct notifier_block *nb, unsigned long event,
++			void *data)
++{
++	struct dev_pm_opp *opp = data;
++	struct private_data *priv = container_of(nb, struct private_data,
++						 opp_nb);
++	struct device *cpu_dev = priv->cpu_dev;
++	struct regulator *cpu_reg;
++	unsigned long volt, freq;
++	int ret = 0;
++
++	if (event == OPP_EVENT_ADJUST_VOLTAGE) {
++		cpu_reg = dev_pm_opp_get_regulator(cpu_dev);
++		if (IS_ERR(cpu_reg)) {
++			ret = PTR_ERR(cpu_reg);
++			goto out;
++		}
++		volt = dev_pm_opp_get_voltage(opp);
++		freq = dev_pm_opp_get_freq(opp);
++
++		mutex_lock(&priv->lock);
++		if (freq == priv->opp_freq) {
++			ret = regulator_set_voltage_triplet(cpu_reg, volt, volt, volt);
++		}
++		mutex_unlock(&priv->lock);
++		if (ret)
++			dev_err(cpu_dev, "failed to scale voltage: %d\n", ret);
++	}
++
++out:
++	return notifier_from_errno(ret);
++}
++
+ static int resources_available(void)
+ {
+	struct device *cpu_dev;
+@@ -152,6 +195,7 @@ static int cpufreq_init(struct cpufreq_p
+	bool fallback = false;
+	const char *name;
+	int ret;
++	struct srcu_notifier_head *opp_srcu_head;
+
+	cpu_dev = get_cpu_device(policy->cpu);
+	if (!cpu_dev) {
+@@ -241,13 +285,16 @@ static int cpufreq_init(struct cpufreq_p
+		goto out_free_opp;
+	}
+
++	mutex_init(&priv->lock);
++	dev_pm_opp_register_notifier(cpu_dev, &priv->opp_nb);
++
+	priv->reg_name = name;
+	priv->opp_table = opp_table;
+
+	ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+-		goto out_free_priv;
++		goto out_unregister_nb;
+	}
+
+	priv->cpu_dev = cpu_dev;
+@@ -283,6 +343,8 @@ static int cpufreq_init(struct cpufreq_p
+
+ out_free_cpufreq_table:
+	dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
++out_unregister_nb:
++	dev_pm_opp_unregister_notifier(cpu_dev, &priv->opp_nb);
+ out_free_priv:
+	kfree(priv);
+ out_free_opp:
diff --git a/target/linux/ipq806x/patches-4.14/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch b/target/linux/ipq806x/patches-4.14/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch
new file mode 100644
index 0000000..1669649
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0055-cpufreq-dt-Add-L2-frequency-scaling-support.patch
@@ -0,0 +1,90 @@ 
+From 0759cdff49f1cf361bf503c13f7bcb33da43ab95 Mon Sep 17 00:00:00 2001
+From: Georgi Djakov <georgi.djakov@linaro.org>
+Date: Tue, 8 Sep 2015 11:24:41 +0300
+Subject: [PATCH 55/69] cpufreq-dt: Add L2 frequency scaling support
+
+Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
+---
+ drivers/cpufreq/cpufreq-dt.c | 41 ++++++++++++++++++++++++++++++++++++++++-
+ include/linux/cpufreq.h      |  2 ++
+ 2 files changed, 42 insertions(+), 1 deletion(-)
+
+--- a/drivers/cpufreq/cpufreq-dt.c
++++ b/drivers/cpufreq/cpufreq-dt.c
+@@ -48,11 +48,41 @@ static int set_target(struct cpufreq_pol
+	struct private_data *priv = policy->driver_data;
+	int ret;
+	unsigned long target_freq = policy->freq_table[index].frequency * 1000;
++	struct clk *l2_clk = policy->l2_clk;
++	unsigned int l2_freq;
++	unsigned long new_l2_freq = 0;
+
+	mutex_lock(&priv->lock);
+	ret = dev_pm_opp_set_rate(priv->cpu_dev, target_freq);
+-	if (!ret)
++
++	if (!ret) {
++		if (!IS_ERR(l2_clk) && policy->l2_rate[0] && policy->l2_rate[1] &&
++				policy->l2_rate[2]) {
++			static unsigned long krait_l2[CONFIG_NR_CPUS] = { };
++			int cpu, ret = 0;
++
++			if (target_freq >= policy->l2_rate[2])
++				new_l2_freq = policy->l2_rate[2];
++			else if (target_freq >= policy->l2_rate[1])
++				new_l2_freq = policy->l2_rate[1];
++			else
++				new_l2_freq = policy->l2_rate[0];
++
++			krait_l2[policy->cpu] = new_l2_freq;
++			for_each_present_cpu(cpu)
++				new_l2_freq = max(new_l2_freq, krait_l2[cpu]);
++
++			l2_freq = clk_get_rate(l2_clk);
++
++			if (l2_freq != new_l2_freq) {
++				/* scale l2 with the core */
++				ret = clk_set_rate(l2_clk, new_l2_freq);
++			}
++		}
++
+		priv->opp_freq = target_freq;
++	}
++
+	mutex_unlock(&priv->lock);
+
+	return ret;
+@@ -196,6 +226,8 @@ static int cpufreq_init(struct cpufreq_p
+	const char *name;
+	int ret;
+	struct srcu_notifier_head *opp_srcu_head;
++	struct device_node *l2_np;
++	struct clk *l2_clk = NULL;
+
+	cpu_dev = get_cpu_device(policy->cpu);
+	if (!cpu_dev) {
+@@ -303,6 +335,13 @@ static int cpufreq_init(struct cpufreq_p
+
+	policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000;
+
++	l2_clk = clk_get(cpu_dev, "l2");
++	if (!IS_ERR(l2_clk))
++		policy->l2_clk = l2_clk;
++	l2_np = of_find_node_by_name(NULL, "qcom,l2");
++	if (l2_np)
++		of_property_read_u32_array(l2_np, "qcom,l2-rates", policy->l2_rate, 3);
++
+	ret = cpufreq_table_validate_and_show(policy, freq_table);
+	if (ret) {
+		dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__,
+--- a/include/linux/cpufreq.h
++++ b/include/linux/cpufreq.h
+@@ -73,6 +73,8 @@ struct cpufreq_policy {
+	unsigned int		cpu;    /* cpu managing this policy, must be online */
+
+	struct clk		*clk;
++	struct clk		*l2_clk; /* L2 clock */
++	unsigned int		l2_rate[3]; /* L2 bus clock rate thresholds */
+	struct cpufreq_cpuinfo	cpuinfo;/* see above */
+
+	unsigned int		min;    /* in kHz */
diff --git a/target/linux/ipq806x/patches-4.14/0056-cpufreq-dt-Add-missing-rcu-locks.patch b/target/linux/ipq806x/patches-4.14/0056-cpufreq-dt-Add-missing-rcu-locks.patch
new file mode 100644
index 0000000..0aae212
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0056-cpufreq-dt-Add-missing-rcu-locks.patch
@@ -0,0 +1,23 @@ 
+From 001a8dcb56ced58c518aaa10a4f0ba5e878705b6 Mon Sep 17 00:00:00 2001
+From: Georgi Djakov <georgi.djakov@linaro.org>
+Date: Tue, 17 May 2016 16:15:43 +0300
+Subject: [PATCH 56/69] cpufreq-dt: Add missing rcu locks
+
+Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
+---
+ drivers/cpufreq/cpufreq-dt.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/cpufreq/cpufreq-dt.c
++++ b/drivers/cpufreq/cpufreq-dt.c
+@@ -143,8 +143,10 @@ static int opp_notifier(struct notifier_
+			ret = PTR_ERR(cpu_reg);
+			goto out;
+		}
++		rcu_read_lock();
+		volt = dev_pm_opp_get_voltage(opp);
+		freq = dev_pm_opp_get_freq(opp);
++		rcu_read_unlock();
+
+		mutex_lock(&priv->lock);
+		if (freq == priv->opp_freq) {
diff --git a/target/linux/ipq806x/patches-4.14/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch b/target/linux/ipq806x/patches-4.14/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch
new file mode 100644
index 0000000..0c8cb8a
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0059-ARM-cpuidle-Add-cpuidle-support-for-QCOM-cpus.patch
@@ -0,0 +1,29 @@ 
+From 04ca10340f1b4d92e849724d322a7ca225d11539 Mon Sep 17 00:00:00 2001
+From: Lina Iyer <lina.iyer@linaro.org>
+Date: Wed, 25 Mar 2015 14:25:29 -0600
+Subject: [PATCH 59/69] ARM: cpuidle: Add cpuidle support for QCOM cpus
+
+Define ARM_QCOM_CPUIDLE config item to enable cpuidle support.
+
+Cc: Stephen Boyd <sboyd@codeaurora.org>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: Kevin Hilman <khilman@linaro.org>
+Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
+Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
+---
+ drivers/cpuidle/Kconfig.arm | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/cpuidle/Kconfig.arm
++++ b/drivers/cpuidle/Kconfig.arm
+@@ -75,3 +75,10 @@ config ARM_MVEBU_V7_CPUIDLE
+	depends on ARCH_MVEBU && !ARM64
+	help
+	  Select this to enable cpuidle on Armada 370, 38x and XP processors.
++
++config ARM_QCOM_CPUIDLE
++	bool "CPU Idle Driver for QCOM processors"
++	depends on ARCH_QCOM
++	select ARM_CPUIDLE
++	help
++	  Select this to enable cpuidle on QCOM processors.
diff --git a/target/linux/ipq806x/patches-4.14/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch b/target/linux/ipq806x/patches-4.14/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch
new file mode 100644
index 0000000..23265e2
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0060-HACK-arch-arm-force-ZRELADDR-on-arch-qcom.patch
@@ -0,0 +1,62 @@ 
+From fa71139b55e114aa8c3c4823ff8ee7d49ee810d4 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu@codeaurora.org>
+Date: Wed, 29 Apr 2015 15:21:46 -0700
+Subject: [PATCH 60/69] HACK: arch: arm: force ZRELADDR on arch-qcom
+
+ARCH_QCOM is using the ARCH_MULTIPLATFORM option, as now recommended
+on most ARM architectures. This automatically calculate ZRELADDR by
+masking PHYS_OFFSET with 0xf8000000.
+
+However, on IPQ806x, the first ~20MB of RAM is reserved for the hardware
+network accelerators, and the bootloader removes this section from the
+layout passed from the ATAGS (when used).
+
+For newer bootloader, when DT is used, this is not a problem, we just
+reserve this memory in the device tree. But if the bootloader doesn't
+have DT support, then ATAGS have to be used. In this case, the ARM
+decompressor will position the kernel in this low mem, which will not be
+in the RAM section mapped by the bootloader, which means the kernel will
+freeze in the middle of the boot process trying to map the memory.
+
+As a work around, this patch allows disabling AUTO_ZRELADDR when
+ARCH_QCOM is selected. It makes the zImage usage possible on bootloaders
+which don't support device-tree, which is the case on certain early
+IPQ806x based designs.
+
+Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+---
+ arch/arm/Kconfig                 | 2 +-
+ arch/arm/Makefile                | 2 ++
+ arch/arm/mach-qcom/Makefile.boot | 1 +
+ 3 files changed, 4 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/mach-qcom/Makefile.boot
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -341,7 +341,7 @@
+	depends on MMU
+	select ARM_HAS_SG_CHAIN
+	select ARM_PATCH_PHYS_VIRT
+-	select AUTO_ZRELADDR
++	select AUTO_ZRELADDR if !ARCH_QCOM
+	select TIMER_OF
+	select COMMON_CLK
+	select GENERIC_CLOCKEVENTS
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -255,9 +255,11 @@ MACHINE  := arch/arm/mach-$(word 1,$(mac
+ else
+ MACHINE  :=
+ endif
++ifeq ($(CONFIG_ARCH_QCOM),)
+ ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y)
+ MACHINE  :=
+ endif
++endif
+
+ machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))
+ platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y)))
+--- /dev/null
++++ b/arch/arm/mach-qcom/Makefile.boot
+@@ -0,0 +1 @@
++zreladdr-y+= 0x42208000
diff --git a/target/linux/ipq806x/patches-4.14/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch b/target/linux/ipq806x/patches-4.14/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch
new file mode 100644
index 0000000..ce18093
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0061-mtd-rootfs-conflicts-with-OpenWrt-auto-mounting.patch
@@ -0,0 +1,23 @@ 
+From 5001f2e1a325b68dbf225bd17f69a4d3d975cca5 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 9 Mar 2017 09:31:44 +0100
+Subject: [PATCH 61/69] mtd: "rootfs" conflicts with OpenWrt auto mounting
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ drivers/mtd/qcom_smem_part.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/mtd/qcom_smem_part.c
++++ b/drivers/mtd/qcom_smem_part.c
+@@ -189,6 +189,10 @@ static int parse_qcom_smem_partitions(st
+		m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz);
+		m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz);
+
++		/* "rootfs" conflicts with OpenWrt auto mounting */
++		if (mtd_type_is_nand(master) && !strcmp(m_part->name, "rootfs"))
++			m_part->name = "ubi";
++
+		/*
+		 * The last SMEM partition may have its size marked as
+		 * something like 0xffffffff, which means "until the end of the
diff --git a/target/linux/ipq806x/patches-4.14/0062-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch b/target/linux/ipq806x/patches-4.14/0062-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch
new file mode 100644
index 0000000..004018c
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0062-ipq806x-gcc-Added-the-enable-regs-and-mask-for-PRNG.patch
@@ -0,0 +1,25 @@ 
+From a16fcf911a020e46439a3bb3e702463fc3159831 Mon Sep 17 00:00:00 2001
+From: Abhishek Sahu <absahu@codeaurora.org>
+Date: Wed, 18 Nov 2015 12:38:56 +0530
+Subject: [PATCH 62/69] ipq806x: gcc: Added the enable regs and mask for PRNG
+
+kernel got hanged while reading from /dev/hwrng at the
+time of PRNG clock enable
+
+Change-Id: I89856c7e19e6639508e6a2774304583a3ec91172
+Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
+---
+ drivers/clk/qcom/gcc-ipq806x.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/clk/qcom/gcc-ipq806x.c
++++ b/drivers/clk/qcom/gcc-ipq806x.c
+@@ -1233,6 +1233,8 @@ static struct clk_rcg prng_src = {
+		.parent_map = gcc_pxo_pll8_map,
+	},
+	.clkr = {
++		.enable_reg = 0x2e80,
++		.enable_mask = BIT(11),
+		.hw.init = &(struct clk_init_data){
+			.name = "prng_src",
+			.parent_names = gcc_pxo_pll8,
diff --git a/target/linux/ipq806x/patches-4.14/0063-1-ipq806x-tsens-driver.patch b/target/linux/ipq806x/patches-4.14/0063-1-ipq806x-tsens-driver.patch
new file mode 100644
index 0000000..b427550
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0063-1-ipq806x-tsens-driver.patch
@@ -0,0 +1,627 @@ 
+From 3302e1e1a3cfa4e67fda2a61d6f0c42205d40932 Mon Sep 17 00:00:00 2001
+From: Rajith Cherian <rajith@codeaurora.org>
+Date: Tue, 14 Feb 2017 18:30:43 +0530
+Subject: [PATCH] ipq8064: tsens: Base tsens driver for IPQ8064
+
+Add TSENS driver template to support IPQ8064.
+This is a base file copied from tsens-8960.c
+
+Change-Id: I47c573fdfa2d898243c6a6ba952d1632f91391f7
+Signed-off-by: Rajith Cherian <rajith@codeaurora.org>
+
+ipq8064: tsens: TSENS driver support for IPQ8064
+
+Support for IPQ8064 tsens driver. The driver works
+with the thermal framework. The driver overrides the
+following fucntionalities:
+
+1. Get current temperature.
+2. Get/Set trip temperatures.
+3. Enabled/Disable trip points.
+4. ISR for threshold generated interrupt.
+5. Notify userspace when trip points are hit.
+
+Change-Id: I8bc7204fd627d10875ab13fc1de8cb6c2ed7a918
+Signed-off-by: Rajith Cherian <rajith@codeaurora.org>
+---
+ .../devicetree/bindings/thermal/qcom-tsens.txt     |   1 +
+ drivers/thermal/qcom/Makefile                      |   3 +-
+ drivers/thermal/qcom/tsens-ipq8064.c               | 551 +++++++++++++++++++++
+ drivers/thermal/qcom/tsens.c                       |   3 +
+ drivers/thermal/qcom/tsens.h                       |   2 +-
+ 5 files changed, 558 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/thermal/qcom/tsens-ipq8064.c
+
+--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
++++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+@@ -5,6 +5,7 @@ Required properties:
+  - "qcom,msm8916-tsens" : For 8916 Family of SoCs
+  - "qcom,msm8974-tsens" : For 8974 Family of SoCs
+  - "qcom,msm8996-tsens" : For 8996 Family of SoCs
++ - "qcom,ipq8064-tsens" : For IPQ8064
+
+ - reg: Address range of the thermal registers
+ - #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
+--- a/drivers/thermal/qcom/Makefile
++++ b/drivers/thermal/qcom/Makefile
+@@ -1,2 +1,3 @@
+ obj-$(CONFIG_QCOM_TSENS)	+= qcom_tsens.o
+-qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-8996.o
++qcom_tsens-y			+= tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-8996.o \
++				tsens-ipq8064.o
+--- /dev/null
++++ b/drivers/thermal/qcom/tsens-ipq8064.c
+@@ -0,0 +1,551 @@
++/*
++ * Copyright (c) 2015, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/regmap.h>
++#include <linux/thermal.h>
++#include <linux/nvmem-consumer.h>
++#include <linux/io.h>
++#include <linux/interrupt.h>
++#include "tsens.h"
++
++#define CAL_MDEGC		30000
++
++#define CONFIG_ADDR		0x3640
++/* CONFIG_ADDR bitmasks */
++#define CONFIG			0x9b
++#define CONFIG_MASK		0xf
++#define CONFIG_SHIFT		0
++
++#define STATUS_CNTL_8064	0x3660
++#define CNTL_ADDR		0x3620
++/* CNTL_ADDR bitmasks */
++#define EN			BIT(0)
++#define SW_RST			BIT(1)
++#define SENSOR0_EN		BIT(3)
++#define SLP_CLK_ENA		BIT(26)
++#define MEASURE_PERIOD		1
++#define SENSOR0_SHIFT		3
++
++/* INT_STATUS_ADDR bitmasks */
++#define MIN_STATUS_MASK		BIT(0)
++#define LOWER_STATUS_CLR	BIT(1)
++#define UPPER_STATUS_CLR	BIT(2)
++#define MAX_STATUS_MASK		BIT(3)
++
++#define THRESHOLD_ADDR		0x3624
++/* THRESHOLD_ADDR bitmasks */
++#define THRESHOLD_MAX_CODE		0x20000
++#define THRESHOLD_MIN_CODE		0
++#define THRESHOLD_MAX_LIMIT_SHIFT	24
++#define THRESHOLD_MIN_LIMIT_SHIFT	16
++#define THRESHOLD_UPPER_LIMIT_SHIFT	8
++#define THRESHOLD_LOWER_LIMIT_SHIFT	0
++#define THRESHOLD_MAX_LIMIT_MASK	(THRESHOLD_MAX_CODE << \
++						THRESHOLD_MAX_LIMIT_SHIFT)
++#define THRESHOLD_MIN_LIMIT_MASK	(THRESHOLD_MAX_CODE << \
++						THRESHOLD_MIN_LIMIT_SHIFT)
++#define THRESHOLD_UPPER_LIMIT_MASK	(THRESHOLD_MAX_CODE << \
++						THRESHOLD_UPPER_LIMIT_SHIFT)
++#define THRESHOLD_LOWER_LIMIT_MASK	(THRESHOLD_MAX_CODE << \
++						THRESHOLD_LOWER_LIMIT_SHIFT)
++
++/* Initial temperature threshold values */
++#define LOWER_LIMIT_TH		0x9d /* 95C */
++#define UPPER_LIMIT_TH		0xa6 /* 105C */
++#define MIN_LIMIT_TH		0x0
++#define MAX_LIMIT_TH		0xff
++
++#define S0_STATUS_ADDR		0x3628
++#define STATUS_ADDR_OFFSET	2
++#define SENSOR_STATUS_SIZE	4
++#define INT_STATUS_ADDR		0x363c
++#define TRDY_MASK		BIT(7)
++#define TIMEOUT_US		100
++
++#define TSENS_EN		BIT(0)
++#define TSENS_SW_RST		BIT(1)
++#define TSENS_ADC_CLK_SEL	BIT(2)
++#define SENSOR0_EN		BIT(3)
++#define SENSOR1_EN		BIT(4)
++#define SENSOR2_EN		BIT(5)
++#define SENSOR3_EN		BIT(6)
++#define SENSOR4_EN		BIT(7)
++#define SENSORS_EN		(SENSOR0_EN | SENSOR1_EN | \
++				SENSOR2_EN | SENSOR3_EN | SENSOR4_EN)
++#define TSENS_8064_SENSOR5_EN				BIT(8)
++#define TSENS_8064_SENSOR6_EN				BIT(9)
++#define TSENS_8064_SENSOR7_EN				BIT(10)
++#define TSENS_8064_SENSOR8_EN				BIT(11)
++#define TSENS_8064_SENSOR9_EN				BIT(12)
++#define TSENS_8064_SENSOR10_EN				BIT(13)
++#define TSENS_8064_SENSORS_EN				(SENSORS_EN | \
++						TSENS_8064_SENSOR5_EN | \
++						TSENS_8064_SENSOR6_EN | \
++						TSENS_8064_SENSOR7_EN | \
++						TSENS_8064_SENSOR8_EN | \
++						TSENS_8064_SENSOR9_EN | \
++						TSENS_8064_SENSOR10_EN)
++
++#define TSENS_8064_SEQ_SENSORS	5
++#define TSENS_8064_S4_S5_OFFSET	40
++#define TSENS_FACTOR		1
++
++/* Trips: from very hot to very cold */
++enum tsens_trip_type {
++	TSENS_TRIP_STAGE3 = 0,
++	TSENS_TRIP_STAGE2,
++	TSENS_TRIP_STAGE1,
++	TSENS_TRIP_STAGE0,
++	TSENS_TRIP_NUM,
++};
++
++u32 tsens_8064_slope[] = {
++			1176, 1176, 1154, 1176,
++			1111, 1132, 1132, 1199,
++			1132, 1199, 1132
++			};
++
++/* Temperature on y axis and ADC-code on x-axis */
++static inline int code_to_degC(u32 adc_code, const struct tsens_sensor *s)
++{
++	int degcbeforefactor, degc;
++
++	degcbeforefactor = (adc_code * s->slope) + s->offset;
++
++	if (degcbeforefactor == 0)
++		degc = degcbeforefactor;
++	else if (degcbeforefactor > 0)
++		degc = (degcbeforefactor + TSENS_FACTOR/2)
++			/ TSENS_FACTOR;
++	else
++		degc = (degcbeforefactor - TSENS_FACTOR/2)
++			/ TSENS_FACTOR;
++
++	return degc;
++}
++
++static int degC_to_code(int degC, const struct tsens_sensor *s)
++{
++	int code = ((degC * TSENS_FACTOR - s->offset) + (s->slope/2))
++			/ s->slope;
++
++	if (code > THRESHOLD_MAX_CODE)
++		code = THRESHOLD_MAX_CODE;
++	else if (code < THRESHOLD_MIN_CODE)
++		code = THRESHOLD_MIN_CODE;
++	return code;
++}
++
++static int suspend_ipq8064(struct tsens_device *tmdev)
++{
++	int ret;
++	unsigned int mask;
++	struct regmap *map = tmdev->map;
++
++	ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold);
++	if (ret)
++		return ret;
++
++	ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control);
++	if (ret)
++		return ret;
++
++	mask = SLP_CLK_ENA | EN;
++
++	ret = regmap_update_bits(map, CNTL_ADDR, mask, 0);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static int resume_ipq8064(struct tsens_device *tmdev)
++{
++	int ret;
++	struct regmap *map = tmdev->map;
++
++	ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
++	if (ret)
++		return ret;
++
++	ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
++	if (ret)
++		return ret;
++
++	ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold);
++	if (ret)
++		return ret;
++
++	ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static void notify_uspace_tsens_fn(struct work_struct *work)
++{
++	struct tsens_sensor *s = container_of(work, struct tsens_sensor,
++								notify_work);
++
++	sysfs_notify(&s->tzd->device.kobj, NULL, "type");
++}
++
++static void tsens_scheduler_fn(struct work_struct *work)
++{
++	struct tsens_device *tmdev = container_of(work, struct tsens_device,
++					tsens_work);
++	unsigned int threshold, threshold_low, code, reg, sensor, mask;
++	unsigned int sensor_addr;
++	bool upper_th_x, lower_th_x;
++	int adc_code, ret;
++
++	ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg);
++	if (ret)
++		return;
++	reg = reg | LOWER_STATUS_CLR | UPPER_STATUS_CLR;
++	ret = regmap_write(tmdev->map, STATUS_CNTL_8064, reg);
++	if (ret)
++		return;
++
++	mask = ~(LOWER_STATUS_CLR | UPPER_STATUS_CLR);
++	ret = regmap_read(tmdev->map, THRESHOLD_ADDR, &threshold);
++	if (ret)
++		return;
++	threshold_low = (threshold & THRESHOLD_LOWER_LIMIT_MASK)
++				>> THRESHOLD_LOWER_LIMIT_SHIFT;
++	threshold = (threshold & THRESHOLD_UPPER_LIMIT_MASK)
++				>> THRESHOLD_UPPER_LIMIT_SHIFT;
++
++	ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg);
++	if (ret)
++		return;
++
++	ret = regmap_read(tmdev->map, CNTL_ADDR, &sensor);
++	if (ret)
++		return;
++	sensor &= (uint32_t) TSENS_8064_SENSORS_EN;
++	sensor >>= SENSOR0_SHIFT;
++
++	/* Constraint: There is only 1 interrupt control register for all
++	 * 11 temperature sensor. So monitoring more than 1 sensor based
++	 * on interrupts will yield inconsistent result. To overcome this
++	 * issue we will monitor only sensor 0 which is the master sensor.
++	 */
++
++	/* Skip if the sensor is disabled */
++	if (sensor & 1) {
++		ret = regmap_read(tmdev->map, tmdev->sensor[0].status, &code);
++		if (ret)
++			return;
++		upper_th_x = code >= threshold;
++		lower_th_x = code <= threshold_low;
++		if (upper_th_x)
++			mask |= UPPER_STATUS_CLR;
++		if (lower_th_x)
++			mask |= LOWER_STATUS_CLR;
++		if (upper_th_x || lower_th_x) {
++			/* Notify user space */
++			schedule_work(&tmdev->sensor[0].notify_work);
++			regmap_read(tmdev->map, sensor_addr, &adc_code);
++			pr_debug("Trigger (%d degrees) for sensor %d\n",
++				code_to_degC(adc_code, &tmdev->sensor[0]), 0);
++		}
++	}
++	regmap_write(tmdev->map, STATUS_CNTL_8064, reg & mask);
++
++	/* force memory to sync */
++	mb();
++}
++
++static irqreturn_t tsens_isr(int irq, void *data)
++{
++	struct tsens_device *tmdev = data;
++
++	schedule_work(&tmdev->tsens_work);
++	return IRQ_HANDLED;
++}
++
++static void hw_init(struct tsens_device *tmdev)
++{
++	int ret;
++	unsigned int reg_cntl = 0, reg_cfg = 0, reg_thr = 0;
++	unsigned int reg_status_cntl = 0;
++
++	regmap_read(tmdev->map, CNTL_ADDR, &reg_cntl);
++	regmap_write(tmdev->map, CNTL_ADDR, reg_cntl | TSENS_SW_RST);
++
++	reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18)
++		| (((1 << tmdev->num_sensors) - 1) << SENSOR0_SHIFT);
++	regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
++	regmap_read(tmdev->map, STATUS_CNTL_8064, &reg_status_cntl);
++	reg_status_cntl |= LOWER_STATUS_CLR | UPPER_STATUS_CLR
++			| MIN_STATUS_MASK | MAX_STATUS_MASK;
++	regmap_write(tmdev->map, STATUS_CNTL_8064, reg_status_cntl);
++	reg_cntl |= TSENS_EN;
++	regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
++
++	regmap_read(tmdev->map, CONFIG_ADDR, &reg_cfg);
++	reg_cfg = (reg_cfg & ~CONFIG_MASK) | (CONFIG << CONFIG_SHIFT);
++	regmap_write(tmdev->map, CONFIG_ADDR, reg_cfg);
++
++	reg_thr |= (LOWER_LIMIT_TH << THRESHOLD_LOWER_LIMIT_SHIFT)
++		| (UPPER_LIMIT_TH << THRESHOLD_UPPER_LIMIT_SHIFT)
++		| (MIN_LIMIT_TH << THRESHOLD_MIN_LIMIT_SHIFT)
++		| (MAX_LIMIT_TH << THRESHOLD_MAX_LIMIT_SHIFT);
++
++	regmap_write(tmdev->map, THRESHOLD_ADDR, reg_thr);
++
++	ret = devm_request_irq(tmdev->dev, tmdev->tsens_irq, tsens_isr,
++			IRQF_TRIGGER_RISING, "tsens_interrupt", tmdev);
++	if (ret < 0) {
++		pr_err("%s: request_irq FAIL: %d\n", __func__, ret);
++		return;
++	}
++
++	INIT_WORK(&tmdev->tsens_work, tsens_scheduler_fn);
++}
++
++static int init_ipq8064(struct tsens_device *tmdev)
++{
++	int ret, i;
++	u32 reg_cntl, offset = 0;
++
++	init_common(tmdev);
++	if (!tmdev->map)
++		return -ENODEV;
++
++	/*
++	 * The status registers for each sensor are discontiguous
++	 * because some SoCs have 5 sensors while others have more
++	 * but the control registers stay in the same place, i.e
++	 * directly after the first 5 status registers.
++	 */
++	for (i = 0; i < tmdev->num_sensors; i++) {
++		if (i >= TSENS_8064_SEQ_SENSORS)
++			offset = TSENS_8064_S4_S5_OFFSET;
++
++		tmdev->sensor[i].status = S0_STATUS_ADDR + offset
++					+ (i << STATUS_ADDR_OFFSET);
++		tmdev->sensor[i].slope = tsens_8064_slope[i];
++		INIT_WORK(&tmdev->sensor[i].notify_work,
++						notify_uspace_tsens_fn);
++	}
++
++	reg_cntl = SW_RST;
++	ret = regmap_update_bits(tmdev->map, CNTL_ADDR, SW_RST, reg_cntl);
++	if (ret)
++		return ret;
++
++	reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
++	reg_cntl &= ~SW_RST;
++	ret = regmap_update_bits(tmdev->map, CONFIG_ADDR,
++					 CONFIG_MASK, CONFIG);
++
++	reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT;
++	ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
++	if (ret)
++		return ret;
++
++	reg_cntl |= EN;
++	ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static int calibrate_ipq8064(struct tsens_device *tmdev)
++{
++	int i;
++	char *data, *data_backup;
++
++	ssize_t num_read = tmdev->num_sensors;
++	struct tsens_sensor *s = tmdev->sensor;
++
++	data = qfprom_read(tmdev->dev, "calib");
++	if (IS_ERR(data)) {
++		pr_err("Calibration not found.\n");
++		return PTR_ERR(data);
++	}
++
++	data_backup = qfprom_read(tmdev->dev, "calib_backup");
++	if (IS_ERR(data_backup)) {
++		pr_err("Backup calibration not found.\n");
++		return PTR_ERR(data_backup);
++	}
++
++	for (i = 0; i < num_read; i++) {
++		s[i].calib_data = readb_relaxed(data + i);
++		s[i].calib_data_backup = readb_relaxed(data_backup + i);
++
++		if (s[i].calib_data_backup)
++			s[i].calib_data = s[i].calib_data_backup;
++		if (!s[i].calib_data) {
++			pr_err("QFPROM TSENS calibration data not present\n");
++			return -ENODEV;
++		}
++		s[i].slope = tsens_8064_slope[i];
++		s[i].offset = CAL_MDEGC - (s[i].calib_data * s[i].slope);
++	}
++
++	hw_init(tmdev);
++
++	return 0;
++}
++
++static int get_temp_ipq8064(struct tsens_device *tmdev, int id, int *temp)
++{
++	int ret;
++	u32 code, trdy;
++	const struct tsens_sensor *s = &tmdev->sensor[id];
++	unsigned long timeout;
++
++	timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
++	do {
++		ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
++		if (ret)
++			return ret;
++		if (!(trdy & TRDY_MASK))
++			continue;
++		ret = regmap_read(tmdev->map, s->status, &code);
++		if (ret)
++			return ret;
++		*temp = code_to_degC(code, s);
++		return 0;
++	} while (time_before(jiffies, timeout));
++
++	return -ETIMEDOUT;
++}
++
++static int set_trip_temp_ipq8064(void *data, int trip, int temp)
++{
++	unsigned int reg_th, reg_cntl;
++	int ret, code, code_chk, hi_code, lo_code;
++	const struct tsens_sensor *s = data;
++	struct tsens_device *tmdev = s->tmdev;
++
++	code_chk = code = degC_to_code(temp, s);
++
++	if (code < THRESHOLD_MIN_CODE || code > THRESHOLD_MAX_CODE)
++		return -EINVAL;
++
++	ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg_cntl);
++	if (ret)
++		return ret;
++
++	ret = regmap_read(tmdev->map, THRESHOLD_ADDR, &reg_th);
++	if (ret)
++		return ret;
++
++	hi_code = (reg_th & THRESHOLD_UPPER_LIMIT_MASK)
++			>> THRESHOLD_UPPER_LIMIT_SHIFT;
++	lo_code = (reg_th & THRESHOLD_LOWER_LIMIT_MASK)
++			>> THRESHOLD_LOWER_LIMIT_SHIFT;
++
++	switch (trip) {
++	case TSENS_TRIP_STAGE3:
++		code <<= THRESHOLD_MAX_LIMIT_SHIFT;
++		reg_th &= ~THRESHOLD_MAX_LIMIT_MASK;
++		break;
++	case TSENS_TRIP_STAGE2:
++		if (code_chk <= lo_code)
++			return -EINVAL;
++		code <<= THRESHOLD_UPPER_LIMIT_SHIFT;
++		reg_th &= ~THRESHOLD_UPPER_LIMIT_MASK;
++		break;
++	case TSENS_TRIP_STAGE1:
++		if (code_chk >= hi_code)
++			return -EINVAL;
++		code <<= THRESHOLD_LOWER_LIMIT_SHIFT;
++		reg_th &= ~THRESHOLD_LOWER_LIMIT_MASK;
++		break;
++	case TSENS_TRIP_STAGE0:
++		code <<= THRESHOLD_MIN_LIMIT_SHIFT;
++		reg_th &= ~THRESHOLD_MIN_LIMIT_MASK;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	ret = regmap_write(tmdev->map, THRESHOLD_ADDR, reg_th | code);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static int set_trip_activate_ipq8064(void *data, int trip,
++					enum thermal_trip_activation_mode mode)
++{
++	unsigned int reg_cntl, mask, val;
++	const struct tsens_sensor *s = data;
++	struct tsens_device *tmdev = s->tmdev;
++	int ret;
++
++	if (!tmdev || trip < 0)
++		return -EINVAL;
++
++	ret = regmap_read(tmdev->map, STATUS_CNTL_8064, &reg_cntl);
++	if (ret)
++		return ret;
++
++	switch (trip) {
++	case TSENS_TRIP_STAGE3:
++		mask = MAX_STATUS_MASK;
++		break;
++	case TSENS_TRIP_STAGE2:
++		mask = UPPER_STATUS_CLR;
++		break;
++	case TSENS_TRIP_STAGE1:
++		mask = LOWER_STATUS_CLR;
++		break;
++	case TSENS_TRIP_STAGE0:
++		mask = MIN_STATUS_MASK;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	if (mode == THERMAL_TRIP_ACTIVATION_DISABLED)
++		val = reg_cntl | mask;
++	else
++		val = reg_cntl & ~mask;
++
++	ret = regmap_write(tmdev->map, STATUS_CNTL_8064, val);
++	if (ret)
++		return ret;
++
++	/* force memory to sync */
++	mb();
++	return 0;
++}
++
++const struct tsens_ops ops_ipq8064 = {
++	.init		= init_ipq8064,
++	.calibrate	= calibrate_ipq8064,
++	.get_temp	= get_temp_ipq8064,
++	.suspend	= suspend_ipq8064,
++	.resume		= resume_ipq8064,
++	.set_trip_temp	= set_trip_temp_ipq8064,
++	.set_trip_activate = set_trip_activate_ipq8064,
++};
++
++const struct tsens_data data_ipq8064 = {
++	.num_sensors	= 11,
++	.ops		= &ops_ipq8064,
++};
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -72,6 +72,9 @@ static const struct of_device_id tsens_t
+	}, {
+		.compatible = "qcom,msm8996-tsens",
+		.data = &data_8996,
++	}, {
++		.compatible = "qcom,ipq8064-tsens",
++		.data = &data_ipq8064,
+	},
+	{}
+ };
+--- a/drivers/thermal/qcom/tsens.h
++++ b/drivers/thermal/qcom/tsens.h
+@@ -89,6 +89,6 @@ void compute_intercept_slope(struct tsen
+ int init_common(struct tsens_device *);
+ int get_temp_common(struct tsens_device *, int, int *);
+
+-extern const struct tsens_data data_8916, data_8974, data_8960, data_8996;
++extern const struct tsens_data data_8916, data_8974, data_8960, data_8996, data_ipq8064;
+
+ #endif /* __QCOM_TSENS_H__ */
diff --git a/target/linux/ipq806x/patches-4.14/0063-2-tsens-support-configurable-interrupts.patch b/target/linux/ipq806x/patches-4.14/0063-2-tsens-support-configurable-interrupts.patch
new file mode 100644
index 0000000..ef270dd
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0063-2-tsens-support-configurable-interrupts.patch
@@ -0,0 +1,453 @@ 
+From 4e87400732c77765afae2ea89ed43837457aa604 Mon Sep 17 00:00:00 2001
+From: Rajith Cherian <rajith@codeaurora.org>
+Date: Wed, 1 Feb 2017 19:00:26 +0530
+Subject: [PATCH] ipq8064: tsens: Support for configurable interrupts
+
+Provide support for adding configurable high and
+configurable low trip temperatures. An interrupts is
+also triggerred when these trip points are hit. The
+interrupts can be activated or deactivated from sysfs.
+This functionality is made available only if
+CONFIG_THERMAL_WRITABLE_TRIPS is defined.
+
+Change-Id: Ib73f3f9459de4fffce7bb985a0312a88291f4934
+Signed-off-by: Rajith Cherian <rajith@codeaurora.org>
+---
+ .../devicetree/bindings/thermal/qcom-tsens.txt     |  4 ++
+ drivers/thermal/of-thermal.c                       | 63 ++++++++++++++++++----
+ drivers/thermal/qcom/tsens.c                       | 43 ++++++++++++---
+ drivers/thermal/qcom/tsens.h                       | 11 ++++
+ drivers/thermal/thermal_core.c                     | 44 ++++++++++++++-
+ include/linux/thermal.h                            | 14 +++++
+ 6 files changed, 162 insertions(+), 17 deletions(-)
+
+--- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
++++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt
+@@ -12,11 +12,15 @@ Required properties:
+ - Refer to Documentation/devicetree/bindings/nvmem/nvmem.txt to know how to specify
+ nvmem cells
+
++Optional properties:
++- interrupts: Interrupt which gets triggered when threshold is hit
++
+ Example:
+ tsens: thermal-sensor@900000 {
+		compatible = "qcom,msm8916-tsens";
+		reg = <0x4a8000 0x2000>;
+		nvmem-cells = <&tsens_caldata>, <&tsens_calsel>;
+		nvmem-cell-names = "caldata", "calsel";
++		interrupts = <0 178 0>;
+		#thermal-sensor-cells = <1>;
+	};
+--- a/drivers/thermal/of-thermal.c
++++ b/drivers/thermal/of-thermal.c
+@@ -95,7 +95,7 @@ static int of_thermal_get_temp(struct th
+ {
+	struct __thermal_zone *data = tz->devdata;
+
+-	if (!data->ops->get_temp)
++	if (!data->ops->get_temp || (data->mode == THERMAL_DEVICE_DISABLED))
+		return -EINVAL;
+
+	return data->ops->get_temp(data->sensor_data, temp);
+@@ -106,7 +106,8 @@ static int of_thermal_set_trips(struct t
+ {
+	struct __thermal_zone *data = tz->devdata;
+
+-	if (!data->ops || !data->ops->set_trips)
++	if (!data->ops || !data->ops->set_trips
++			|| (data->mode == THERMAL_DEVICE_DISABLED))
+		return -EINVAL;
+
+	return data->ops->set_trips(data->sensor_data, low, high);
+@@ -192,6 +193,9 @@ static int of_thermal_set_emul_temp(stru
+ {
+	struct __thermal_zone *data = tz->devdata;
+
++	if (data->mode == THERMAL_DEVICE_DISABLED)
++		return -EINVAL;
++
+	return data->ops->set_emul_temp(data->sensor_data, temp);
+ }
+
+@@ -200,7 +204,7 @@ static int of_thermal_get_trend(struct t
+ {
+	struct __thermal_zone *data = tz->devdata;
+
+-	if (!data->ops->get_trend)
++	if (!data->ops->get_trend || (data->mode == THERMAL_DEVICE_DISABLED))
+		return -EINVAL;
+
+	return data->ops->get_trend(data->sensor_data, trip, trend);
+@@ -286,7 +290,9 @@ static int of_thermal_set_mode(struct th
+	mutex_unlock(&tz->lock);
+
+	data->mode = mode;
+-	thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
++
++	if (mode == THERMAL_DEVICE_ENABLED)
++		thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+
+	return 0;
+ }
+@@ -296,7 +302,8 @@ static int of_thermal_get_trip_type(stru
+ {
+	struct __thermal_zone *data = tz->devdata;
+
+-	if (trip >= data->ntrips || trip < 0)
++	if (trip >= data->ntrips || trip < 0
++				|| (data->mode == THERMAL_DEVICE_DISABLED))
+		return -EDOM;
+
+	*type = data->trips[trip].type;
+@@ -304,12 +311,39 @@ static int of_thermal_get_trip_type(stru
+	return 0;
+ }
+
++static int of_thermal_activate_trip_type(struct thermal_zone_device *tz,
++			int trip, enum thermal_trip_activation_mode mode)
++{
++	struct __thermal_zone *data = tz->devdata;
++
++	if (trip >= data->ntrips || trip < 0
++				|| (data->mode == THERMAL_DEVICE_DISABLED))
++		return -EDOM;
++
++	/*
++	 * The configurable_hi and configurable_lo trip points can be
++	 * activated and deactivated.
++	 */
++
++	if (data->ops->set_trip_activate) {
++		int ret;
++
++		ret = data->ops->set_trip_activate(data->sensor_data,
++								trip, mode);
++		if (ret)
++			return ret;
++	}
++
++	return 0;
++}
++
+ static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
+				    int *temp)
+ {
+	struct __thermal_zone *data = tz->devdata;
+
+-	if (trip >= data->ntrips || trip < 0)
++	if (trip >= data->ntrips || trip < 0
++				|| (data->mode == THERMAL_DEVICE_DISABLED))
+		return -EDOM;
+
+	*temp = data->trips[trip].temperature;
+@@ -322,7 +356,8 @@ static int of_thermal_set_trip_temp(stru
+ {
+	struct __thermal_zone *data = tz->devdata;
+
+-	if (trip >= data->ntrips || trip < 0)
++	if (trip >= data->ntrips || trip < 0
++				|| (data->mode == THERMAL_DEVICE_DISABLED))
+		return -EDOM;
+
+	if (data->ops->set_trip_temp) {
+@@ -344,7 +379,8 @@ static int of_thermal_get_trip_hyst(stru
+ {
+	struct __thermal_zone *data = tz->devdata;
+
+-	if (trip >= data->ntrips || trip < 0)
++	if (trip >= data->ntrips || trip < 0
++				|| (data->mode == THERMAL_DEVICE_DISABLED))
+		return -EDOM;
+
+	*hyst = data->trips[trip].hysteresis;
+@@ -357,7 +393,8 @@ static int of_thermal_set_trip_hyst(stru
+ {
+	struct __thermal_zone *data = tz->devdata;
+
+-	if (trip >= data->ntrips || trip < 0)
++	if (trip >= data->ntrips || trip < 0
++				|| (data->mode == THERMAL_DEVICE_DISABLED))
+		return -EDOM;
+
+	/* thermal framework should take care of data->mask & (1 << trip) */
+@@ -432,6 +469,9 @@ thermal_zone_of_add_sensor(struct device
+	if (ops->set_emul_temp)
+		tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
+
++	if (ops->set_trip_activate)
++		tzd->ops->set_trip_activate = of_thermal_activate_trip_type;
++
+	mutex_unlock(&tzd->lock);
+
+	return tzd;
+@@ -726,7 +766,10 @@ static const char * const trip_types[] =
+	[THERMAL_TRIP_ACTIVE]	= "active",
+	[THERMAL_TRIP_PASSIVE]	= "passive",
+	[THERMAL_TRIP_HOT]	= "hot",
+-	[THERMAL_TRIP_CRITICAL]	= "critical",
++	[THERMAL_TRIP_CRITICAL]	= "critical_high",
++	[THERMAL_TRIP_CONFIGURABLE_HI] = "configurable_hi",
++	[THERMAL_TRIP_CONFIGURABLE_LOW] = "configurable_lo",
++	[THERMAL_TRIP_CRITICAL_LOW] = "critical_low",
+ };
+
+ /**
+--- a/drivers/thermal/qcom/tsens.c
++++ b/drivers/thermal/qcom/tsens.c
+@@ -31,7 +31,7 @@ static int tsens_get_temp(void *data, in
+
+ static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend)
+ {
+-	const struct tsens_sensor *s = p;
++	struct tsens_sensor *s = p;
+	struct tsens_device *tmdev = s->tmdev;
+
+	if (tmdev->ops->get_trend)
+@@ -40,9 +40,10 @@ static int tsens_get_trend(void *p, int
+	return -ENOTSUPP;
+ }
+
+-static int  __maybe_unused tsens_suspend(struct device *dev)
++static int  __maybe_unused tsens_suspend(void *data)
+ {
+-	struct tsens_device *tmdev = dev_get_drvdata(dev);
++	struct tsens_sensor *s = data;
++	struct tsens_device *tmdev = s->tmdev;
+
+	if (tmdev->ops && tmdev->ops->suspend)
+		return tmdev->ops->suspend(tmdev);
+@@ -50,9 +51,10 @@ static int  __maybe_unused tsens_suspend
+	return 0;
+ }
+
+-static int __maybe_unused tsens_resume(struct device *dev)
++static int __maybe_unused tsens_resume(void *data)
+ {
+-	struct tsens_device *tmdev = dev_get_drvdata(dev);
++	struct tsens_sensor *s = data;
++	struct tsens_device *tmdev = s->tmdev;
+
+	if (tmdev->ops && tmdev->ops->resume)
+		return tmdev->ops->resume(tmdev);
+@@ -60,6 +62,30 @@ static int __maybe_unused tsens_resume(s
+	return 0;
+ }
+
++static int  __maybe_unused tsens_set_trip_temp(void *data, int trip, int temp)
++{
++	struct tsens_sensor *s = data;
++	struct tsens_device *tmdev = s->tmdev;
++
++	if (tmdev->ops && tmdev->ops->set_trip_temp)
++		return tmdev->ops->set_trip_temp(s, trip, temp);
++
++	return 0;
++}
++
++static int __maybe_unused tsens_activate_trip_type(void *data, int trip,
++					enum thermal_trip_activation_mode mode)
++{
++	struct tsens_sensor *s = data;
++	struct tsens_device *tmdev = s->tmdev;
++
++	if (tmdev->ops && tmdev->ops->set_trip_activate)
++		return tmdev->ops->set_trip_activate(s, trip, mode);
++
++	return 0;
++}
++
++
+ static SIMPLE_DEV_PM_OPS(tsens_pm_ops, tsens_suspend, tsens_resume);
+
+ static const struct of_device_id tsens_table[] = {
+@@ -83,6 +109,8 @@ MODULE_DEVICE_TABLE(of, tsens_table);
+ static const struct thermal_zone_of_device_ops tsens_of_ops = {
+	.get_temp = tsens_get_temp,
+	.get_trend = tsens_get_trend,
++	.set_trip_temp = tsens_set_trip_temp,
++	.set_trip_activate = tsens_activate_trip_type,
+ };
+
+ static int tsens_register(struct tsens_device *tmdev)
+@@ -131,7 +159,7 @@ static int tsens_probe(struct platform_d
+	if (id)
+		data = id->data;
+	else
+-		data = &data_8960;
++		return -EINVAL;
+
+	if (data->num_sensors <= 0) {
+		dev_err(dev, "invalid number of sensors\n");
+@@ -146,6 +174,9 @@ static int tsens_probe(struct platform_d
+	tmdev->dev = dev;
+	tmdev->num_sensors = data->num_sensors;
+	tmdev->ops = data->ops;
++
++	tmdev->tsens_irq = platform_get_irq(pdev, 0);
++
+	for (i = 0;  i < tmdev->num_sensors; i++) {
+		if (data->hw_ids)
+			tmdev->sensor[i].hw_id = data->hw_ids[i];
+--- a/drivers/thermal/qcom/tsens.h
++++ b/drivers/thermal/qcom/tsens.h
+@@ -24,9 +24,12 @@ struct tsens_device;
+ struct tsens_sensor {
+	struct tsens_device		*tmdev;
+	struct thermal_zone_device	*tzd;
++	struct work_struct		notify_work;
+	int				offset;
+	int				id;
+	int				hw_id;
++	int				calib_data;
++	int				calib_data_backup;
+	int				slope;
+	u32				status;
+ };
+@@ -41,6 +44,9 @@ struct tsens_sensor {
+  * @suspend: Function to suspend the tsens device
+  * @resume: Function to resume the tsens device
+  * @get_trend: Function to get the thermal/temp trend
++ * @set_trip_temp: Function to set trip temp
++ * @get_trip_temp: Function to get trip temp
++ * @set_trip_activate: Function to activate trip points
+  */
+ struct tsens_ops {
+	/* mandatory callbacks */
+@@ -53,6 +59,9 @@ struct tsens_ops {
+	int (*suspend)(struct tsens_device *);
+	int (*resume)(struct tsens_device *);
+	int (*get_trend)(struct tsens_device *, int, enum thermal_trend *);
++	int (*set_trip_temp)(void *, int, int);
++	int (*set_trip_activate)(void *, int,
++					enum thermal_trip_activation_mode);
+ };
+
+ /**
+@@ -76,11 +85,13 @@ struct tsens_context {
+ struct tsens_device {
+	struct device			*dev;
+	u32				num_sensors;
++	u32				tsens_irq;
+	struct regmap			*map;
+	struct regmap_field		*status_field;
+	struct tsens_context		ctx;
+	bool				trdy;
+	const struct tsens_ops		*ops;
++	struct work_struct		tsens_work;
+	struct tsens_sensor		sensor[0];
+ };
+
+--- a/drivers/thermal/thermal_sysfs.c
++++ b/drivers/thermal/thermal_sysfs.c
+@@ -115,12 +115,48 @@
+		return sprintf(buf, "passive\n");
+	case THERMAL_TRIP_ACTIVE:
+		return sprintf(buf, "active\n");
++	case THERMAL_TRIP_CONFIGURABLE_HI:
++		return sprintf(buf, "configurable_hi\n");
++	case THERMAL_TRIP_CONFIGURABLE_LOW:
++		return sprintf(buf, "configurable_low\n");
++	case THERMAL_TRIP_CRITICAL_LOW:
++		return sprintf(buf, "critical_low\n");
+	default:
+		return sprintf(buf, "unknown\n");
+	}
+ }
+
+ static ssize_t
++trip_point_type_activate(struct device *dev, struct device_attribute *attr,
++						const char *buf, size_t count)
++{
++	struct thermal_zone_device *tz = to_thermal_zone(dev);
++	int trip, ret;
++	char *enabled = "enabled";
++	char *disabled = "disabled";
++
++	if (!tz->ops->set_trip_activate)
++		return -EPERM;
++
++	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
++		return -EINVAL;
++
++	if (!strncmp(buf, enabled, strlen(enabled)))
++		ret = tz->ops->set_trip_activate(tz, trip,
++				THERMAL_TRIP_ACTIVATION_ENABLED);
++	else if (!strncmp(buf, disabled, strlen(disabled)))
++		ret = tz->ops->set_trip_activate(tz, trip,
++				THERMAL_TRIP_ACTIVATION_DISABLED);
++	else
++		ret = -EINVAL;
++
++	if (ret)
++		return ret;
++
++	return count;
++}
++
++static ssize_t
+ trip_point_temp_store(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+ {
+@@ -562,6 +598,12 @@
+		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
+		attrs[indx] = &tz->trip_type_attrs[indx].attr.attr;
+
++		if (IS_ENABLED(CONFIG_THERMAL_WRITABLE_TRIPS)) {
++			tz->trip_type_attrs[indx].attr.store
++						= trip_point_type_activate;
++			tz->trip_type_attrs[indx].attr.attr.mode |= S_IWUSR;
++		}
++
+		/* create trip temp attribute */
+		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
+			 "trip_point_%d_temp", indx);
+--- a/include/linux/thermal.h
++++ b/include/linux/thermal.h
+@@ -78,11 +78,19 @@ enum thermal_device_mode {
+	THERMAL_DEVICE_ENABLED,
+ };
+
++enum thermal_trip_activation_mode {
++	THERMAL_TRIP_ACTIVATION_DISABLED = 0,
++	THERMAL_TRIP_ACTIVATION_ENABLED,
++};
++
+ enum thermal_trip_type {
+	THERMAL_TRIP_ACTIVE = 0,
+	THERMAL_TRIP_PASSIVE,
+	THERMAL_TRIP_HOT,
+	THERMAL_TRIP_CRITICAL,
++	THERMAL_TRIP_CONFIGURABLE_HI,
++	THERMAL_TRIP_CONFIGURABLE_LOW,
++	THERMAL_TRIP_CRITICAL_LOW,
+ };
+
+ enum thermal_trend {
+@@ -120,6 +128,8 @@ struct thermal_zone_device_ops {
+		enum thermal_trip_type *);
+	int (*get_trip_temp) (struct thermal_zone_device *, int, int *);
+	int (*set_trip_temp) (struct thermal_zone_device *, int, int);
++	int (*set_trip_activate) (struct thermal_zone_device *, int,
++					enum thermal_trip_activation_mode);
+	int (*get_trip_hyst) (struct thermal_zone_device *, int, int *);
+	int (*set_trip_hyst) (struct thermal_zone_device *, int, int);
+	int (*get_crit_temp) (struct thermal_zone_device *, int *);
+@@ -363,6 +373,8 @@ struct thermal_genl_event {
+  *		   temperature.
+  * @set_trip_temp: a pointer to a function that sets the trip temperature on
+  *		   hardware.
++ * @activate_trip_type: a pointer to a function to enable/disable trip
++ *		temperature interrupts
+  */
+ struct thermal_zone_of_device_ops {
+	int (*get_temp)(void *, int *);
+@@ -370,6 +382,8 @@ struct thermal_zone_of_device_ops {
+	int (*set_trips)(void *, int, int);
+	int (*set_emul_temp)(void *, int);
+	int (*set_trip_temp)(void *, int, int);
++	int (*set_trip_activate)(void *, int,
++				enum thermal_trip_activation_mode);
+ };
+
+ /**
diff --git a/target/linux/ipq806x/patches-4.14/0064-clk-clk-rpm-fixes.patch b/target/linux/ipq806x/patches-4.14/0064-clk-clk-rpm-fixes.patch
new file mode 100644
index 0000000..8a6bc1a
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0064-clk-clk-rpm-fixes.patch
@@ -0,0 +1,93 @@ 
+From d30840e2b1cf79d90392e6051b0c0b6006d29d8b Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 9 Mar 2017 09:32:40 +0100
+Subject: [PATCH 64/69] clk: clk-rpm fixes
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ .../devicetree/bindings/clock/qcom,rpmcc.txt       |  1 +
+ drivers/clk/qcom/clk-rpm.c                         | 35 ++++++++++++++++++++++
+ include/dt-bindings/clock/qcom,rpmcc.h             |  4 +++
+ 3 files changed, 40 insertions(+)
+
+--- a/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt
++++ b/Documentation/devicetree/bindings/clock/qcom,rpmcc.txt
+@@ -13,6 +13,7 @@ Required properties :
+			"qcom,rpmcc-msm8916", "qcom,rpmcc"
+			"qcom,rpmcc-msm8974", "qcom,rpmcc"
+			"qcom,rpmcc-apq8064", "qcom,rpmcc"
++			"qcom,rpmcc-ipq806x", "qcom,rpmcc"
+
+ - #clock-cells : shall contain 1
+
+--- a/drivers/clk/qcom/clk-rpm.c
++++ b/drivers/clk/qcom/clk-rpm.c
+@@ -359,6 +359,16 @@ DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a
+ DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK);
+ DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK);
+
++/* ipq806x */
++DEFINE_CLK_RPM(ipq806x, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK);
++DEFINE_CLK_RPM(ipq806x, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK);
++DEFINE_CLK_RPM(ipq806x, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK);
++DEFINE_CLK_RPM(ipq806x, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK);
++DEFINE_CLK_RPM(ipq806x, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK);
++DEFINE_CLK_RPM(ipq806x, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK);
++DEFINE_CLK_RPM(ipq806x, nss_fabric_0_clk, nss_fabric_0_a_clk, QCOM_RPM_NSS_FABRIC_0_CLK);
++DEFINE_CLK_RPM(ipq806x, nss_fabric_1_clk, nss_fabric_1_a_clk, QCOM_RPM_NSS_FABRIC_1_CLK);
++
+ static struct clk_rpm *apq8064_clks[] = {
+	[RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk,
+	[RPM_APPS_FABRIC_A_CLK] = &apq8064_afab_a_clk,
+@@ -380,13 +390,38 @@ static struct clk_rpm *apq8064_clks[] =
+	[RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk,
+ };
+
++static struct clk_rpm *ipq806x_clks[] = {
++	[RPM_APPS_FABRIC_CLK] = &ipq806x_afab_clk,
++	[RPM_APPS_FABRIC_A_CLK] = &ipq806x_afab_a_clk,
++	[RPM_CFPB_CLK] = &ipq806x_cfpb_clk,
++	[RPM_CFPB_A_CLK] = &ipq806x_cfpb_a_clk,
++	[RPM_DAYTONA_FABRIC_CLK] = &ipq806x_daytona_clk,
++	[RPM_DAYTONA_FABRIC_A_CLK] = &ipq806x_daytona_a_clk,
++	[RPM_EBI1_CLK] = &ipq806x_ebi1_clk,
++	[RPM_EBI1_A_CLK] = &ipq806x_ebi1_a_clk,
++	[RPM_SYS_FABRIC_CLK] = &ipq806x_sfab_clk,
++	[RPM_SYS_FABRIC_A_CLK] = &ipq806x_sfab_a_clk,
++	[RPM_SFPB_CLK] = &ipq806x_sfpb_clk,
++	[RPM_SFPB_A_CLK] = &ipq806x_sfpb_a_clk,
++	[RPM_NSS_FABRIC_0_CLK] = &ipq806x_nss_fabric_0_clk,
++	[RPM_NSS_FABRIC_0_A_CLK] = &ipq806x_nss_fabric_0_a_clk,
++	[RPM_NSS_FABRIC_1_CLK] = &ipq806x_nss_fabric_1_clk,
++	[RPM_NSS_FABRIC_1_A_CLK] = &ipq806x_nss_fabric_1_a_clk,
++};
++
+ static const struct rpm_clk_desc rpm_clk_apq8064 = {
+	.clks = apq8064_clks,
+	.num_clks = ARRAY_SIZE(apq8064_clks),
+ };
+
++static const struct rpm_clk_desc rpm_clk_ipq806x = {
++	.clks = ipq806x_clks,
++	.num_clks = ARRAY_SIZE(ipq806x_clks),
++};
++
+ static const struct of_device_id rpm_clk_match_table[] = {
+	{ .compatible = "qcom,rpmcc-apq8064", .data = &rpm_clk_apq8064 },
++	{ .compatible = "qcom,rpmcc-ipq806x", .data = &rpm_clk_ipq806x },
+	{ }
+ };
+ MODULE_DEVICE_TABLE(of, rpm_clk_match_table);
+--- a/include/dt-bindings/clock/qcom,rpmcc.h
++++ b/include/dt-bindings/clock/qcom,rpmcc.h
+@@ -37,6 +37,10 @@
+ #define RPM_SYS_FABRIC_A_CLK			19
+ #define RPM_SFPB_CLK				20
+ #define RPM_SFPB_A_CLK				21
++#define RPM_NSS_FABRIC_0_CLK				22
++#define RPM_NSS_FABRIC_0_A_CLK				23
++#define RPM_NSS_FABRIC_1_CLK				24
++#define RPM_NSS_FABRIC_1_A_CLK				25
+
+ /* SMD RPM clocks */
+ #define RPM_SMD_XO_CLK_SRC				0
diff --git a/target/linux/ipq806x/patches-4.14/0065-arm-override-compiler-flags.patch b/target/linux/ipq806x/patches-4.14/0065-arm-override-compiler-flags.patch
new file mode 100644
index 0000000..0d2a427
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0065-arm-override-compiler-flags.patch
@@ -0,0 +1,21 @@ 
+From 4d8e29642661397a339ac3485f212c6360445421 Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 9 Mar 2017 09:33:32 +0100
+Subject: [PATCH 65/69] arm: override compiler flags
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ arch/arm/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/arm/Makefile
++++ b/arch/arm/Makefile
+@@ -67,7 +67,7 @@ KBUILD_CFLAGS	+= $(call cc-option,-fno-i
+ # macro, but instead defines a whole series of macros which makes
+ # testing for a specific architecture or later rather impossible.
+ arch-$(CONFIG_CPU_32v7M)	=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
+-arch-$(CONFIG_CPU_32v7)		=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
++arch-$(CONFIG_CPU_32v7)		=-D__LINUX_ARM_ARCH__=7 -mcpu=cortex-a15
+ arch-$(CONFIG_CPU_32v6)		=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
+ # Only override the compiler option if ARMv6. The ARMv6K extensions are
+ # always available in ARMv7
diff --git a/target/linux/ipq806x/patches-4.14/0066-GPIO-add-named-gpio-exports.patch b/target/linux/ipq806x/patches-4.14/0066-GPIO-add-named-gpio-exports.patch
new file mode 100644
index 0000000..992c240
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0066-GPIO-add-named-gpio-exports.patch
@@ -0,0 +1,166 @@ 
+From a37b0c9113647b2120cf1a18cfc46afdb3f1fccc Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 12 Aug 2014 20:49:27 +0200
+Subject: [PATCH 66/69] GPIO: add named gpio exports
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/gpio/gpiolib-of.c     | 68 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/gpio/gpiolib-sysfs.c  | 10 ++++++-
+ include/asm-generic/gpio.h    |  6 ++++
+ include/linux/gpio/consumer.h |  8 +++++
+ 4 files changed, 91 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpiolib-of.c
++++ b/drivers/gpio/gpiolib-of.c
+@@ -23,6 +23,8 @@
+ #include <linux/pinctrl/pinctrl.h>
+ #include <linux/slab.h>
+ #include <linux/gpio/machine.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
+
+ #include "gpiolib.h"
+
+@@ -506,3 +508,69 @@ void of_gpiochip_remove(struct gpio_chip
+	gpiochip_remove_pin_ranges(chip);
+	of_node_put(chip->of_node);
+ }
++
++static struct of_device_id gpio_export_ids[] = {
++	{ .compatible = "gpio-export" },
++	{ /* sentinel */ }
++};
++
++static int __init of_gpio_export_probe(struct platform_device *pdev)
++{
++	struct device_node *np = pdev->dev.of_node;
++	struct device_node *cnp;
++	u32 val;
++	int nb = 0;
++
++	for_each_child_of_node(np, cnp) {
++		const char *name = NULL;
++		int gpio;
++		bool dmc;
++		int max_gpio = 1;
++		int i;
++
++		of_property_read_string(cnp, "gpio-export,name", &name);
++
++		if (!name)
++			max_gpio = of_gpio_count(cnp);
++
++		for (i = 0; i < max_gpio; i++) {
++			unsigned flags = 0;
++			enum of_gpio_flags of_flags;
++
++			gpio = of_get_gpio_flags(cnp, i, &of_flags);
++
++			if (of_flags == OF_GPIO_ACTIVE_LOW)
++				flags |= GPIOF_ACTIVE_LOW;
++
++			if (!of_property_read_u32(cnp, "gpio-export,output", &val))
++				flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
++			else
++				flags |= GPIOF_IN;
++
++			if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
++				continue;
++
++			dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
++			gpio_export_with_name(gpio, dmc, name);
++			nb++;
++		}
++	}
++
++	dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
++
++	return 0;
++}
++
++static struct platform_driver gpio_export_driver = {
++	.driver		= {
++		.name		= "gpio-export",
++		.owner	= THIS_MODULE,
++		.of_match_table	= of_match_ptr(gpio_export_ids),
++	},
++};
++
++static int __init of_gpio_export_init(void)
++{
++	return platform_driver_probe(&gpio_export_driver, of_gpio_export_probe);
++}
++device_initcall(of_gpio_export_init);
+--- a/drivers/gpio/gpiolib-sysfs.c
++++ b/drivers/gpio/gpiolib-sysfs.c
+@@ -553,7 +553,7 @@ static struct class gpio_class = {
+  *
+  * Returns zero on success, else an error.
+  */
+-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
+ {
+	struct gpio_chip	*chip;
+	struct gpio_device	*gdev;
+@@ -615,6 +615,8 @@ int gpiod_export(struct gpio_desc *desc,
+	offset = gpio_chip_hwgpio(desc);
+	if (chip->names && chip->names[offset])
+		ioname = chip->names[offset];
++	if (name)
++		ioname = name;
+
+	dev = device_create_with_groups(&gpio_class, &gdev->dev,
+					MKDEV(0, 0), data, gpio_groups,
+@@ -636,6 +638,12 @@ err_unlock:
+	gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+	return status;
+ }
++EXPORT_SYMBOL_GPL(__gpiod_export);
++
++int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++{
++	return __gpiod_export(desc, direction_may_change, NULL);
++}
+ EXPORT_SYMBOL_GPL(gpiod_export);
+
+ static int match_export(struct device *dev, const void *desc)
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -127,6 +127,12 @@ static inline int gpio_export(unsigned g
+	return gpiod_export(gpio_to_desc(gpio), direction_may_change);
+ }
+
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
++static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
++{
++	return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
++}
++
+ static inline int gpio_export_link(struct device *dev, const char *name,
+				   unsigned gpio)
+ {
+--- a/include/linux/gpio/consumer.h
++++ b/include/linux/gpio/consumer.h
+@@ -451,6 +451,7 @@ static inline struct gpio_desc *devm_get
+
+ #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
+
++int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
+ int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
+ int gpiod_export_link(struct device *dev, const char *name,
+		      struct gpio_desc *desc);
+@@ -458,6 +459,13 @@ void gpiod_unexport(struct gpio_desc *de
+
+ #else  /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
+
++static inline int _gpiod_export(struct gpio_desc *desc,
++			       bool direction_may_change,
++			       const char *name)
++{
++	return -ENOSYS;
++}
++
+ static inline int gpiod_export(struct gpio_desc *desc,
+			       bool direction_may_change)
+ {
diff --git a/target/linux/ipq806x/patches-4.14/0067-generic-Mangle-bootloader-s-kernel-arguments.patch b/target/linux/ipq806x/patches-4.14/0067-generic-Mangle-bootloader-s-kernel-arguments.patch
new file mode 100644
index 0000000..98c2ba1
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0067-generic-Mangle-bootloader-s-kernel-arguments.patch
@@ -0,0 +1,189 @@ 
+From 71270226b14733a4b1f2cde58ea9265caa50b38d Mon Sep 17 00:00:00 2001
+From: Adrian Panella <ianchi74@outlook.com>
+Date: Thu, 9 Mar 2017 09:37:17 +0100
+Subject: [PATCH 67/69] generic: Mangle bootloader's kernel arguments
+
+The command-line arguments provided by the boot loader will be
+appended to a new device tree property: bootloader-args.
+If there is a property "append-rootblock" in DT under /chosen
+and a root= option in bootloaders command line it will be parsed
+and added to DT bootargs with the form: <append-rootblock>XX.
+Only command line ATAG will be processed, the rest of the ATAGs
+sent by bootloader will be ignored.
+This is usefull in dual boot systems, to get the current root partition
+without afecting the rest of the system.
+
+Signed-off-by: Adrian Panella <ianchi74@outlook.com>
+---
+ arch/arm/Kconfig                        | 11 +++++
+ arch/arm/boot/compressed/atags_to_fdt.c | 72 ++++++++++++++++++++++++++++++++-
+ init/main.c                             | 16 ++++++++
+ 3 files changed, 98 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1938,6 +1938,17 @@ config ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEN
+	  The command-line arguments provided by the boot loader will be
+	  appended to the the device tree bootargs property.
+
++config ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE
++	bool "Append rootblock parsing bootloader's kernel arguments"
++	help
++	  The command-line arguments provided by the boot loader will be
++	  appended to a new device tree property: bootloader-args.
++	  If there is a property "append-rootblock" in DT under /chosen
++	  and a root= option in bootloaders command line it will be parsed
++	  and added to DT bootargs with the form: <append-rootblock>XX.
++	  Only command line ATAG will be processed, the rest of the ATAGs
++	  sent by bootloader will be ignored.
++
+ endchoice
+
+ config CMDLINE
+--- a/arch/arm/boot/compressed/atags_to_fdt.c
++++ b/arch/arm/boot/compressed/atags_to_fdt.c
+@@ -4,6 +4,8 @@
+
+ #if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND)
+ #define do_extend_cmdline 1
++#elif defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
++#define do_extend_cmdline 1
+ #else
+ #define do_extend_cmdline 0
+ #endif
+@@ -67,6 +69,59 @@ static uint32_t get_cell_size(const void
+	return cell_size;
+ }
+
++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
++
++static char *append_rootblock(char *dest, const char *str, int len, void *fdt)
++{
++	char *ptr, *end;
++	char *root="root=";
++	int i, l;
++	const char *rootblock;
++
++	//ARM doesn't have __HAVE_ARCH_STRSTR, so search manually
++	ptr = str - 1;
++
++	do {
++		//first find an 'r' at the begining or after a space
++		do {
++			ptr++;
++			ptr = strchr(ptr, 'r');
++			if(!ptr) return dest;
++
++		} while (ptr != str && *(ptr-1) != ' ');
++
++		//then check for the rest
++		for(i = 1; i <= 4; i++)
++			if(*(ptr+i) != *(root+i)) break;
++
++	} while (i != 5);
++
++	end = strchr(ptr, ' ');
++	end = end ? (end - 1) : (strchr(ptr, 0) - 1);
++
++	//find partition number (assumes format root=/dev/mtdXX | /dev/mtdblockXX | yy:XX )
++	for( i = 0; end >= ptr && *end >= '0' && *end <= '9'; end--, i++);
++	ptr = end + 1;
++
++	/* if append-rootblock property is set use it to append to command line */
++	rootblock = getprop(fdt, "/chosen", "append-rootblock", &l);
++	if(rootblock != NULL) {
++		if(*dest != ' ') {
++			*dest = ' ';
++			dest++;
++			len++;
++		}
++		if (len + l + i <= COMMAND_LINE_SIZE) {
++			memcpy(dest, rootblock, l);
++			dest += l - 1;
++			memcpy(dest, ptr, i);
++			dest += i;
++		}
++	}
++	return dest;
++}
++#endif
++
+ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
+ {
+	char cmdline[COMMAND_LINE_SIZE];
+@@ -86,12 +141,21 @@ static void merge_fdt_bootargs(void *fdt
+
+	/* and append the ATAG_CMDLINE */
+	if (fdt_cmdline) {
++
++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
++		//save original bootloader args
++		//and append ubi.mtd with root partition number to current cmdline
++		setprop_string(fdt, "/chosen", "bootloader-args", fdt_cmdline);
++		ptr = append_rootblock(ptr, fdt_cmdline, len, fdt);
++
++#else
+		len = strlen(fdt_cmdline);
+		if (ptr - cmdline + len + 2 < COMMAND_LINE_SIZE) {
+			*ptr++ = ' ';
+			memcpy(ptr, fdt_cmdline, len);
+			ptr += len;
+		}
++#endif
+	}
+	*ptr = '\0';
+
+@@ -148,7 +212,9 @@ int atags_to_fdt(void *atag_list, void *
+			else
+				setprop_string(fdt, "/chosen", "bootargs",
+					       atag->u.cmdline.cmdline);
+-		} else if (atag->hdr.tag == ATAG_MEM) {
++		}
++#ifndef CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE
++		else if (atag->hdr.tag == ATAG_MEM) {
+			if (memcount >= sizeof(mem_reg_property)/4)
+				continue;
+			if (!atag->u.mem.size)
+@@ -187,6 +253,10 @@ int atags_to_fdt(void *atag_list, void *
+		setprop(fdt, "/memory", "reg", mem_reg_property,
+			4 * memcount * memsize);
+	}
++#else
++
++	}
++#endif
+
+	return fdt_pack(fdt);
+ }
+--- a/init/main.c
++++ b/init/main.c
+@@ -95,6 +95,10 @@
+ #include <asm/sections.h>
+ #include <asm/cacheflush.h>
+
++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
++#include <linux/of.h>
++#endif
++
+ static int kernel_init(void *);
+
+ extern void init_IRQ(void);
+@@ -574,6 +578,18 @@ asmlinkage __visible void __init start_k
+	page_alloc_init();
+
+	pr_notice("Kernel command line: %s\n", boot_command_line);
++
++#if defined(CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_MANGLE)
++	//Show bootloader's original command line for reference
++	if(of_chosen) {
++		const char *prop = of_get_property(of_chosen, "bootloader-args", NULL);
++		if(prop)
++			pr_notice("Bootloader command line (ignored): %s\n", prop);
++		else
++			pr_notice("Bootloader command line not present\n");
++	}
++#endif
++
+	parse_early_param();
+	after_dashes = parse_args("Booting kernel",
+				  static_command_line, __start___param,
diff --git a/target/linux/ipq806x/patches-4.14/0069-arm-boot-add-dts-files.patch b/target/linux/ipq806x/patches-4.14/0069-arm-boot-add-dts-files.patch
new file mode 100644
index 0000000..d9cd2bb
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0069-arm-boot-add-dts-files.patch
@@ -0,0 +1,28 @@ 
+From 8f68331e14dff9a101f2d0e1d6bec84a031f27ee Mon Sep 17 00:00:00 2001
+From: John Crispin <john@phrozen.org>
+Date: Thu, 9 Mar 2017 11:03:18 +0100
+Subject: [PATCH 69/69] arm: boot: add dts files
+
+Signed-off-by: John Crispin <john@phrozen.org>
+---
+ arch/arm/boot/dts/Makefile | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -699,6 +699,15 @@ dtb-$(CONFIG_ARCH_QCOM) += \
+	qcom-apq8084-mtp.dtb \
+	qcom-ipq4019-ap.dk01.1-c1.dtb \
+	qcom-ipq8064-ap148.dtb \
++	qcom-ipq8064-c2600.dtb \
++	qcom-ipq8064-d7800.dtb \
++	qcom-ipq8064-db149.dtb \
++	qcom-ipq8064-ea8500.dtb \
++	qcom-ipq8064-r7500.dtb \
++	qcom-ipq8064-r7500v2.dtb \
++	qcom-ipq8064-wpq864.dtb \
++	qcom-ipq8065-nbg6817.dtb \
++	qcom-ipq8065-r7800.dtb \
+	qcom-msm8660-surf.dtb \
+	qcom-msm8960-cdp.dtb \
+	qcom-msm8974-lge-nexus5-hammerhead.dtb \
diff --git a/target/linux/ipq806x/patches-4.14/0070-qcom-spm-fix-probe-order.patch b/target/linux/ipq806x/patches-4.14/0070-qcom-spm-fix-probe-order.patch
new file mode 100644
index 0000000..78bc5fc
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0070-qcom-spm-fix-probe-order.patch
@@ -0,0 +1,16 @@ 
+Check for SCM availability before attempting to use SPM
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+
+--- a/drivers/soc/qcom/spm.c
++++ b/drivers/soc/qcom/spm.c
+@@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(stru
+	cpumask_t mask;
+	bool use_scm_power_down = false;
+
++	if (!qcom_scm_is_available())
++		return -EPROBE_DEFER;
++
+	for (i = 0; ; i++) {
+		state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
+		if (!state_node)
diff --git a/target/linux/ipq806x/patches-4.14/0071-1-PCI-qcom-Fixed-IPQ806x-specific-clocks.patch b/target/linux/ipq806x/patches-4.14/0071-1-PCI-qcom-Fixed-IPQ806x-specific-clocks.patch
new file mode 100644
index 0000000..550c92e
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0071-1-PCI-qcom-Fixed-IPQ806x-specific-clocks.patch
@@ -0,0 +1,95 @@ 
+From 86655aa14304ca88a8ce8847276147dbc1a83238 Mon Sep 17 00:00:00 2001
+From: Sham Muthayyan <smuthayy@codeaurora.org>
+Date: Tue, 19 Jul 2016 18:44:49 +0530
+Subject: PCI: qcom: Fixed IPQ806x specific clocks
+
+Change-Id: I488e1bc707d6a22b37a338f41935e3922009ba5e
+Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
+---
+ drivers/pci/host/pcie-qcom.c | 38 +++++++++++++++++++++++++++++++++-----
+ 1 file changed, 33 insertions(+), 5 deletions(-)
+
+--- a/drivers/pci/dwc/pcie-qcom.c
++++ b/drivers/pci/dwc/pcie-qcom.c
+@@ -91,6 +91,8 @@
+	struct clk *iface_clk;
+	struct clk *core_clk;
+	struct clk *phy_clk;
++	struct clk *aux_clk;
++	struct clk *ref_clk;
+	struct reset_control *pci_reset;
+	struct reset_control *axi_reset;
+	struct reset_control *ahb_reset;
+@@ -249,6 +251,14 @@
+	if (IS_ERR(res->phy_clk))
+		return PTR_ERR(res->phy_clk);
+
++	res->aux_clk = devm_clk_get(dev, "aux");
++	if (IS_ERR(res->aux_clk))
++		return PTR_ERR(res->aux_clk);
++
++	res->ref_clk = devm_clk_get(dev, "ref");
++	if (IS_ERR(res->ref_clk))
++		return PTR_ERR(res->ref_clk);
++
+	res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
+	if (IS_ERR(res->pci_reset))
+		return PTR_ERR(res->pci_reset);
+@@ -281,6 +291,8 @@
+	clk_disable_unprepare(res->iface_clk);
+	clk_disable_unprepare(res->core_clk);
+	clk_disable_unprepare(res->phy_clk);
++	clk_disable_unprepare(res->aux_clk);
++	clk_disable_unprepare(res->ref_clk);
+	regulator_disable(res->vdda);
+	regulator_disable(res->vdda_phy);
+	regulator_disable(res->vdda_refclk);
+@@ -324,16 +336,28 @@
+		goto err_assert_ahb;
+	}
+
++	ret = clk_prepare_enable(res->core_clk);
++	if (ret) {
++		dev_err(dev, "cannot prepare/enable core clock\n");
++		goto err_clk_core;
++	}
++
+	ret = clk_prepare_enable(res->phy_clk);
+	if (ret) {
+		dev_err(dev, "cannot prepare/enable phy clock\n");
+		goto err_clk_phy;
+	}
+
+-	ret = clk_prepare_enable(res->core_clk);
++	ret = clk_prepare_enable(res->aux_clk);
+	if (ret) {
+-		dev_err(dev, "cannot prepare/enable core clock\n");
+-		goto err_clk_core;
++		dev_err(dev, "cannot prepare/enable aux clock\n");
++		goto err_clk_aux;
++	}
++
++	ret = clk_prepare_enable(res->ref_clk);
++	if (ret) {
++		dev_err(dev, "cannot prepare/enable ref clock\n");
++		goto err_clk_ref;
+	}
+
+	ret = reset_control_deassert(res->ahb_reset);
+@@ -389,10 +413,14 @@
+	return 0;
+
+ err_deassert_ahb:
+-	clk_disable_unprepare(res->core_clk);
+-err_clk_core:
++	clk_disable_unprepare(res->ref_clk);
++err_clk_ref:
++	clk_disable_unprepare(res->aux_clk);
++err_clk_aux:
+	clk_disable_unprepare(res->phy_clk);
+ err_clk_phy:
++	clk_disable_unprepare(res->core_clk);
++err_clk_core:
+	clk_disable_unprepare(res->iface_clk);
+ err_assert_ahb:
+	regulator_disable(res->vdda_phy);
diff --git a/target/linux/ipq806x/patches-4.14/0071-2-PCI-qcom-Fixed-IPQ806x-PCIE-reset-changes.patch b/target/linux/ipq806x/patches-4.14/0071-2-PCI-qcom-Fixed-IPQ806x-PCIE-reset-changes.patch
new file mode 100644
index 0000000..a2ae1e0
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0071-2-PCI-qcom-Fixed-IPQ806x-PCIE-reset-changes.patch
@@ -0,0 +1,85 @@ 
+From 490d103232287eb51c92c49a4ef8865fd0a9d59e Mon Sep 17 00:00:00 2001
+From: Sham Muthayyan <smuthayy@codeaurora.org>
+Date: Tue, 19 Jul 2016 18:58:18 +0530
+Subject: PCI: qcom: Fixed IPQ806x PCIE reset changes
+
+Change-Id: Ia6590e960b9754b1e8b7a51f318788cd63e9e321
+Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
+---
+ drivers/pci/host/pcie-qcom.c | 24 +++++++++++++++++++-----
+ 1 file changed, 19 insertions(+), 5 deletions(-)
+
+--- a/drivers/pci/dwc/pcie-qcom.c
++++ b/drivers/pci/dwc/pcie-qcom.c
+@@ -98,6 +98,7 @@
+ 	struct reset_control *ahb_reset;
+ 	struct reset_control *por_reset;
+ 	struct reset_control *phy_reset;
++	struct reset_control *ext_reset;
+ 	struct regulator *vdda;
+ 	struct regulator *vdda_phy;
+ 	struct regulator *vdda_refclk;
+@@ -275,6 +276,10 @@
+ 	if (IS_ERR(res->por_reset))
+ 		return PTR_ERR(res->por_reset);
+
++	res->ext_reset = devm_reset_control_get(dev, "ext");
++	if (IS_ERR(res->ext_reset))
++		return PTR_ERR(res->ext_reset);
++
+ 	res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
+ 	return PTR_ERR_OR_ZERO(res->phy_reset);
+ }
+@@ -288,6 +293,7 @@
+ 	reset_control_assert(res->ahb_reset);
+ 	reset_control_assert(res->por_reset);
+ 	reset_control_assert(res->pci_reset);
++	reset_control_assert(res->ext_reset);
+ 	clk_disable_unprepare(res->iface_clk);
+ 	clk_disable_unprepare(res->core_clk);
+ 	clk_disable_unprepare(res->phy_clk);
+@@ -306,6 +312,12 @@
+ 	u32 val;
+ 	int ret;
+
++	ret = reset_control_assert(res->ahb_reset);
++	if (ret) {
++		dev_err(dev, "cannot assert ahb reset\n");
++		return ret;
++	}
++
+ 	ret = regulator_enable(res->vdda);
+ 	if (ret) {
+ 		dev_err(dev, "cannot enable vdda regulator\n");
+@@ -324,16 +336,16 @@
+ 		goto err_vdda_phy;
+ 	}
+
+-	ret = reset_control_assert(res->ahb_reset);
++	ret = reset_control_deassert(res->ext_reset);
+ 	if (ret) {
+-		dev_err(dev, "cannot assert ahb reset\n");
+-		goto err_assert_ahb;
++		dev_err(dev, "cannot assert ext reset\n");
++		goto err_reset_ext;
+ 	}
+
+ 	ret = clk_prepare_enable(res->iface_clk);
+ 	if (ret) {
+ 		dev_err(dev, "cannot prepare/enable iface clock\n");
+-		goto err_assert_ahb;
++		goto err_iface;
+ 	}
+
+ 	ret = clk_prepare_enable(res->core_clk);
+@@ -422,7 +434,9 @@
+ 	clk_disable_unprepare(res->core_clk);
+ err_clk_core:
+ 	clk_disable_unprepare(res->iface_clk);
+-err_assert_ahb:
++err_iface:
++	reset_control_assert(res->ext_reset);
++err_reset_ext:
+ 	regulator_disable(res->vdda_phy);
+ err_vdda_phy:
+ 	regulator_disable(res->vdda_refclk);
diff --git a/target/linux/ipq806x/patches-4.14/0071-3-PCI-qcom-Fixed-IPQ806x-PCIE-init-changes.patch b/target/linux/ipq806x/patches-4.14/0071-3-PCI-qcom-Fixed-IPQ806x-PCIE-init-changes.patch
new file mode 100644
index 0000000..0c2910f
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0071-3-PCI-qcom-Fixed-IPQ806x-PCIE-init-changes.patch
@@ -0,0 +1,126 @@ 
+From eddd13215d0f2b549ebc5f0e8796d5b1231f90a0 Mon Sep 17 00:00:00 2001
+From: Sham Muthayyan <smuthayy@codeaurora.org>
+Date: Tue, 19 Jul 2016 19:58:22 +0530
+Subject: PCI: qcom: Fixed IPQ806x PCIE init changes
+
+Change-Id: Ic319b1aec27a47809284759f8fcb6a8815b7cf7e
+Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
+---
+ drivers/pci/host/pcie-qcom.c | 62 +++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 53 insertions(+), 9 deletions(-)
+
+--- a/drivers/pci/dwc/pcie-qcom.c
++++ b/drivers/pci/dwc/pcie-qcom.c
+@@ -52,7 +52,13 @@
+ #define PCIE_CAP_CPL_TIMEOUT_DISABLE		0x10
+
+ #define PCIE20_PARF_PHY_CTRL			0x40
++#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK	(0x1f << 16)
++#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x)		(x << 16)
++
+ #define PCIE20_PARF_PHY_REFCLK			0x4C
++#define REF_SSP_EN				BIT(16)
++#define REF_USE_PAD				BIT(12)
++
+ #define PCIE20_PARF_DBI_BASE_ADDR		0x168
+ #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE		0x16C
+ #define PCIE20_PARF_MHI_CLOCK_RESET_CTRL	0x174
+@@ -83,6 +89,18 @@
+ #define DBI_RO_WR_EN				1
+
+ #define PERST_DELAY_US				1000
++/* PARF registers */
++#define PCIE20_PARF_PCS_DEEMPH			0x34
++#define PCS_DEEMPH_TX_DEEMPH_GEN1(x)		(x << 16)
++#define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x)	(x << 8)
++#define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x)	(x << 0)
++
++#define PCIE20_PARF_PCS_SWING			0x38
++#define PCS_SWING_TX_SWING_FULL(x)		(x << 8)
++#define PCS_SWING_TX_SWING_LOW(x)		(x << 0)
++
++#define PCIE20_PARF_CONFIG_BITS			0x50
++#define PHY_RX0_EQ(x)				(x << 24)
+
+ #define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE	0x358
+ #define SLV_ADDR_SPACE_SZ			0x10000000
+@@ -102,6 +120,7 @@
+ 	struct regulator *vdda;
+ 	struct regulator *vdda_phy;
+ 	struct regulator *vdda_refclk;
++	uint8_t phy_tx0_term_offset;
+ };
+
+ struct qcom_pcie_resources_1_0_0 {
+@@ -179,6 +198,16 @@
+
+ #define to_qcom_pcie(x)		dev_get_drvdata((x)->dev)
+
++static inline void
++writel_masked(void __iomem *addr, u32 clear_mask, u32 set_mask)
++{
++	u32 val = readl(addr);
++
++	val &= ~clear_mask;
++	val |= set_mask;
++	writel(val, addr);
++}
++
+ static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
+ {
+ 	gpiod_set_value_cansleep(pcie->reset, 1);
+@@ -280,6 +309,10 @@
+ 	if (IS_ERR(res->ext_reset))
+ 		return PTR_ERR(res->ext_reset);
+
++	if (of_property_read_u8(dev->of_node, "phy-tx0-term-offset",
++				&res->phy_tx0_term_offset))
++		res->phy_tx0_term_offset = 0;
++
+ 	res->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
+ 	return PTR_ERR_OR_ZERO(res->phy_reset);
+ }
+@@ -309,7 +342,6 @@
+ 	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
+ 	struct dw_pcie *pci = pcie->pci;
+ 	struct device *dev = pci->dev;
+-	u32 val;
+ 	int ret;
+
+ 	ret = reset_control_assert(res->ahb_reset);
+@@ -378,15 +410,26 @@
+ 		goto err_deassert_ahb;
+ 	}
+
+-	/* enable PCIe clocks and resets */
+-	val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL);
+-	val &= ~BIT(0);
+-	writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL);
+-
+-	/* enable external reference clock */
+-	val = readl(pcie->parf + PCIE20_PARF_PHY_REFCLK);
+-	val |= BIT(16);
+-	writel(val, pcie->parf + PCIE20_PARF_PHY_REFCLK);
++	writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
++
++	/* Set Tx termination offset */
++	writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL,
++		      PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK,
++		      PHY_CTRL_PHY_TX0_TERM_OFFSET(res->phy_tx0_term_offset));
++
++	/* PARF programming */
++	writel(PCS_DEEMPH_TX_DEEMPH_GEN1(0x18) |
++	       PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(0x18) |
++	       PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(0x22),
++	       pcie->parf + PCIE20_PARF_PCS_DEEMPH);
++	writel(PCS_SWING_TX_SWING_FULL(0x78) |
++	       PCS_SWING_TX_SWING_LOW(0x78),
++	       pcie->parf + PCIE20_PARF_PCS_SWING);
++	writel(PHY_RX0_EQ(0x4), pcie->parf + PCIE20_PARF_CONFIG_BITS);
++
++	/* Enable reference clock */
++	writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK,
++		      REF_USE_PAD, REF_SSP_EN);
+
+ 	ret = reset_control_deassert(res->phy_reset);
+ 	if (ret) {
diff --git a/target/linux/ipq806x/patches-4.14/0071-5-PCI-qcom-Programming-the-PCIE-iATU-for-IPQ806x.patch b/target/linux/ipq806x/patches-4.14/0071-5-PCI-qcom-Programming-the-PCIE-iATU-for-IPQ806x.patch
new file mode 100644
index 0000000..1b19d6f
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0071-5-PCI-qcom-Programming-the-PCIE-iATU-for-IPQ806x.patch
@@ -0,0 +1,114 @@ 
+From d27c303e828d7e42f339a459d2abfe30c51698e9 Mon Sep 17 00:00:00 2001
+From: Sham Muthayyan <smuthayy@codeaurora.org>
+Date: Tue, 26 Jul 2016 12:28:31 +0530
+Subject: PCI: qcom: Programming the PCIE iATU for IPQ806x
+
+Resolved PCIE EP detection errors caused due to missing iATU programming.
+
+Change-Id: Ie95c0f8cb940abc0192a8a3c4e825ddba54b72fe
+Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
+---
+ drivers/pci/host/pcie-qcom.c | 77 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 77 insertions(+)
+
+--- a/drivers/pci/dwc/pcie-qcom.c
++++ b/drivers/pci/dwc/pcie-qcom.c
+@@ -83,6 +83,30 @@
+ #define PCIE20_CAP_LINK_1			(PCIE20_CAP + 0x14)
+ #define PCIE_CAP_LINK1_VAL			0x2FD7F
+
++#define PCIE20_CAP_LINKCTRLSTATUS		(PCIE20_CAP + 0x10)
++
++#define PCIE20_AXI_MSTR_RESP_COMP_CTRL0		0x818
++#define PCIE20_AXI_MSTR_RESP_COMP_CTRL1		0x81c
++
++#define PCIE20_PLR_IATU_VIEWPORT		0x900
++#define PCIE20_PLR_IATU_REGION_OUTBOUND		(0x0 << 31)
++#define PCIE20_PLR_IATU_REGION_INDEX(x)		(x << 0)
++
++#define PCIE20_PLR_IATU_CTRL1			0x904
++#define PCIE20_PLR_IATU_TYPE_CFG0		(0x4 << 0)
++#define PCIE20_PLR_IATU_TYPE_MEM		(0x0 << 0)
++
++#define PCIE20_PLR_IATU_CTRL2			0x908
++#define PCIE20_PLR_IATU_ENABLE			BIT(31)
++
++#define PCIE20_PLR_IATU_LBAR			0x90C
++#define PCIE20_PLR_IATU_UBAR			0x910
++#define PCIE20_PLR_IATU_LAR			0x914
++#define PCIE20_PLR_IATU_LTAR			0x918
++#define PCIE20_PLR_IATU_UTAR			0x91c
++
++#define MSM_PCIE_DEV_CFG_ADDR			0x01000000
++
+ #define PCIE20_PARF_Q2A_FLUSH			0x1AC
+
+ #define PCIE20_MISC_CONTROL_1_REG		0x8BC
+@@ -251,6 +275,57 @@
+	writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL);
+ }
+
++static void qcom_pcie_prog_viewport_cfg0(struct qcom_pcie *pcie, u32 busdev)
++{
++	struct pcie_port *pp = &pcie->pci->pp;
++
++	/*
++	 * program and enable address translation region 0 (device config
++	 * address space); region type config;
++	 * axi config address range to device config address range
++	 */
++	writel(PCIE20_PLR_IATU_REGION_OUTBOUND |
++	       PCIE20_PLR_IATU_REGION_INDEX(0),
++	       pcie->pci->dbi_base + PCIE20_PLR_IATU_VIEWPORT);
++
++	writel(PCIE20_PLR_IATU_TYPE_CFG0, pcie->pci->dbi_base + PCIE20_PLR_IATU_CTRL1);
++	writel(PCIE20_PLR_IATU_ENABLE, pcie->pci->dbi_base + PCIE20_PLR_IATU_CTRL2);
++	writel(pp->cfg0_base, pcie->pci->dbi_base + PCIE20_PLR_IATU_LBAR);
++	writel((pp->cfg0_base >> 32), pcie->pci->dbi_base + PCIE20_PLR_IATU_UBAR);
++	writel((pp->cfg0_base + pp->cfg0_size - 1),
++	       pcie->pci->dbi_base + PCIE20_PLR_IATU_LAR);
++	writel(busdev, pcie->pci->dbi_base + PCIE20_PLR_IATU_LTAR);
++	writel(0, pcie->pci->dbi_base + PCIE20_PLR_IATU_UTAR);
++}
++
++static void qcom_pcie_prog_viewport_mem2_outbound(struct qcom_pcie *pcie)
++{
++	struct pcie_port *pp = &pcie->pci->pp;
++
++	/*
++	 * program and enable address translation region 2 (device resource
++	 * address space); region type memory;
++	 * axi device bar address range to device bar address range
++	 */
++	writel(PCIE20_PLR_IATU_REGION_OUTBOUND |
++	       PCIE20_PLR_IATU_REGION_INDEX(2),
++	       pcie->pci->dbi_base + PCIE20_PLR_IATU_VIEWPORT);
++
++	writel(PCIE20_PLR_IATU_TYPE_MEM, pcie->pci->dbi_base + PCIE20_PLR_IATU_CTRL1);
++	writel(PCIE20_PLR_IATU_ENABLE, pcie->pci->dbi_base + PCIE20_PLR_IATU_CTRL2);
++	writel(pp->mem_base, pcie->pci->dbi_base + PCIE20_PLR_IATU_LBAR);
++	writel((pp->mem_base >> 32), pcie->pci->dbi_base + PCIE20_PLR_IATU_UBAR);
++	writel(pp->mem_base + pp->mem_size - 1,
++	       pcie->pci->dbi_base + PCIE20_PLR_IATU_LAR);
++	writel(pp->mem_bus_addr, pcie->pci->dbi_base + PCIE20_PLR_IATU_LTAR);
++	writel(upper_32_bits(pp->mem_bus_addr),
++	       pcie->pci->dbi_base + PCIE20_PLR_IATU_UTAR);
++
++	/* 256B PCIE buffer setting */
++	writel(0x1, pcie->pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL0);
++	writel(0x1, pcie->pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL1);
++}
++
+ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
+ {
+	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
+@@ -465,6 +538,9 @@
+	writel(CFG_BRIDGE_SB_INIT,
+	       pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL1);
+
++	qcom_pcie_prog_viewport_cfg0(pcie, MSM_PCIE_DEV_CFG_ADDR);
++	qcom_pcie_prog_viewport_mem2_outbound(pcie);
++
+	return 0;
+
+ err_deassert_ahb:
diff --git a/target/linux/ipq806x/patches-4.14/0071-6-PCI-qcom-Force-GEN1-support.patch b/target/linux/ipq806x/patches-4.14/0071-6-PCI-qcom-Force-GEN1-support.patch
new file mode 100644
index 0000000..f623532
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0071-6-PCI-qcom-Force-GEN1-support.patch
@@ -0,0 +1,61 @@ 
+From 4910cfd150342ec7b038892262923c725a9c4001 Mon Sep 17 00:00:00 2001
+From: Sham Muthayyan <smuthayy@codeaurora.org>
+Date: Wed, 7 Sep 2016 16:44:28 +0530
+Subject: PCI: qcom: Force GEN1 support
+
+Change-Id: Ica54ddb737d7b851469deab1745f54bf431bd3f0
+Signed-off-by: Sham Muthayyan <smuthayy@codeaurora.org>
+---
+ drivers/pci/host/pcie-qcom.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/drivers/pci/dwc/pcie-qcom.c
++++ b/drivers/pci/dwc/pcie-qcom.c
+@@ -129,6 +129,8 @@
+ #define PCIE20_v3_PARF_SLV_ADDR_SPACE_SIZE	0x358
+ #define SLV_ADDR_SPACE_SZ			0x10000000
+
++#define PCIE20_LNK_CONTROL2_LINK_STATUS2        0xA0
++
+ struct qcom_pcie_resources_2_1_0 {
+	struct clk *iface_clk;
+	struct clk *core_clk;
+@@ -218,6 +220,7 @@
+	struct phy *phy;
+	struct gpio_desc *reset;
+	struct qcom_pcie_ops *ops;
++	uint32_t force_gen1;
+ };
+
+ #define to_qcom_pcie(x)		dev_get_drvdata((x)->dev)
+@@ -532,6 +535,11 @@
+
+	/* wait for clock acquisition */
+	usleep_range(1000, 1500);
++	if (pcie->force_gen1) {
++		writel_relaxed((readl_relaxed(
++			pcie->pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2) | 1),
++			pcie->pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2);
++	}
+
+
+	/* Set the Max TLP size to 2K, instead of using default of 4K */
+@@ -1382,6 +1390,8 @@
+	struct dw_pcie *pci;
+	struct qcom_pcie *pcie;
+	int ret;
++	uint32_t force_gen1 = 0;
++	struct device_node *np = pdev->dev.of_node;
+
+	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+	if (!pcie)
+@@ -1403,6 +1413,9 @@
+	if (IS_ERR(pcie->reset))
+		return PTR_ERR(pcie->reset);
+
++	of_property_read_u32(np, "force_gen1", &force_gen1);
++	pcie->force_gen1 = force_gen1;
++
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf");
+	pcie->parf = devm_ioremap_resource(dev, res);
+	if (IS_ERR(pcie->parf))
diff --git a/target/linux/ipq806x/patches-4.14/0071-7-pcie-Set-PCIE-MRRS-and-MPS-to-256B.patch b/target/linux/ipq806x/patches-4.14/0071-7-pcie-Set-PCIE-MRRS-and-MPS-to-256B.patch
new file mode 100644
index 0000000..c70cd0b
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0071-7-pcie-Set-PCIE-MRRS-and-MPS-to-256B.patch
@@ -0,0 +1,69 @@ 
+From edff8f777c6321ca89bb950a382f409c4a126e28 Mon Sep 17 00:00:00 2001
+From: Gokul Sriram Palanisamy <gpalan@codeaurora.org>
+Date: Thu, 15 Dec 2016 17:38:18 +0530
+Subject: pcie: Set PCIE MRRS and MPS to 256B
+
+Set Max Read Request Size and Max Payload Size to 256 bytes,
+per chip team recommendation.
+
+Change-Id: I097004be2ced1b3096ffc10c318aae0b2bb155e8
+Signed-off-by: Gokul Sriram Palanisamy <gpalan@codeaurora.org>
+---
+ drivers/pci/host/pcie-qcom.c | 37 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+(limited to 'drivers/pci/host/pcie-qcom.c')
+
+--- a/drivers/pci/dwc/pcie-qcom.c
++++ b/drivers/pci/dwc/pcie-qcom.c
+@@ -131,6 +131,14 @@
+
+ #define PCIE20_LNK_CONTROL2_LINK_STATUS2        0xA0
+
++#define __set(v, a, b)	(((v) << (b)) & GENMASK(a, b))
++#define __mask(a, b)	(((1 << ((a) + 1)) - 1) & ~((1 << (b)) - 1))
++#define PCIE20_DEV_CAS			0x78
++#define PCIE20_MRRS_MASK		__mask(14, 12)
++#define PCIE20_MRRS(x)			__set(x, 14, 12)
++#define PCIE20_MPS_MASK			__mask(7, 5)
++#define PCIE20_MPS(x)			__set(x, 7, 5)
++
+ struct qcom_pcie_resources_2_1_0 {
+	struct clk *iface_clk;
+	struct clk *core_clk;
+@@ -1472,6 +1480,35 @@
+	return 0;
+ }
+
++static void qcom_pcie_fixup_final(struct pci_dev *dev)
++{
++	int cap, err;
++	u16 ctl, reg_val;
++
++	cap = pci_pcie_cap(dev);
++	if (!cap)
++		return;
++
++	err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
++
++	if (err)
++		return;
++
++	reg_val = ctl;
++
++	if (((reg_val & PCIE20_MRRS_MASK) >> 12) > 1)
++		reg_val = (reg_val & ~(PCIE20_MRRS_MASK)) | PCIE20_MRRS(0x1);
++
++	if (((ctl & PCIE20_MPS_MASK) >> 5) > 1)
++		reg_val = (reg_val & ~(PCIE20_MPS_MASK)) | PCIE20_MPS(0x1);
++
++	err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, reg_val);
++
++	if (err)
++		pr_err("pcie config write failed %d\n", err);
++}
++DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, qcom_pcie_fixup_final);
++
+ static const struct of_device_id qcom_pcie_match[] = {
+	{ .compatible = "qcom,pcie-apq8084", .data = &ops_1_0_0 },
+	{ .compatible = "qcom,pcie-ipq8064", .data = &ops_2_1_0 },
diff --git a/target/linux/ipq806x/patches-4.14/0071-8-pcie-qcom-Fixed-pcie_phy_clk-branch-issue.patch b/target/linux/ipq806x/patches-4.14/0071-8-pcie-qcom-Fixed-pcie_phy_clk-branch-issue.patch
new file mode 100644
index 0000000..74f666d
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0071-8-pcie-qcom-Fixed-pcie_phy_clk-branch-issue.patch
@@ -0,0 +1,91 @@ 
+From b74bab6186131eea09459eedf5d737645a3559c9 Mon Sep 17 00:00:00 2001
+From: Abhishek Sahu <absahu@codeaurora.org>
+Date: Thu, 22 Dec 2016 11:18:45 +0530
+Subject: pcie: qcom: Fixed pcie_phy_clk branch issue
+
+Following backtraces are observed in PCIe deinit operation.
+
+ Hardware name: Qualcomm (Flattened Device Tree)
+ (unwind_backtrace) from [] (show_stack+0x10/0x14)
+ (show_stack) from [] (dump_stack+0x84/0x98)
+ (dump_stack) from [] (warn_slowpath_common+0x9c/0xb8)
+ (warn_slowpath_common) from [] (warn_slowpath_fmt+0x30/0x40)
+ (warn_slowpath_fmt) from [] (clk_branch_wait+0x114/0x120)
+ (clk_branch_wait) from [] (clk_core_disable+0xd0/0x1f4)
+ (clk_core_disable) from [] (clk_disable+0x24/0x30)
+ (clk_disable) from [] (qcom_pcie_deinit_v0+0x6c/0xb8)
+ (qcom_pcie_deinit_v0) from [] (qcom_pcie_host_init+0xe0/0xe8)
+ (qcom_pcie_host_init) from [] (dw_pcie_host_init+0x3b0/0x538)
+ (dw_pcie_host_init) from [] (qcom_pcie_probe+0x20c/0x2e4)
+
+pcie_phy_clk is generated for PCIe controller itself and the
+GCC controls its branch operation. This error is coming since
+the assert operations turn off the parent clock before branch
+clock. Now this patch moves clk_disable_unprepare before assert
+operations.
+
+Similarly, during probe function, the clock branch operation
+should be done after dessert operation. Currently, it does not
+generate any error since bootloader enables the pcie_phy_clk
+but the same error is coming during probe, if bootloader
+disables pcie_phy_clk.
+
+Change-Id: Ib29c154d10eb64363d9cc982ce5fd8107af5627d
+Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
+---
+ drivers/pci/host/pcie-qcom.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+--- a/drivers/pci/dwc/pcie-qcom.c
++++ b/drivers/pci/dwc/pcie-qcom.c
+@@ -407,6 +407,7 @@
+ {
+	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
+
++	clk_disable_unprepare(res->phy_clk);
+	reset_control_assert(res->pci_reset);
+	reset_control_assert(res->axi_reset);
+	reset_control_assert(res->ahb_reset);
+@@ -415,7 +415,6 @@
+	reset_control_assert(res->ext_reset);
+	clk_disable_unprepare(res->iface_clk);
+	clk_disable_unprepare(res->core_clk);
+-	clk_disable_unprepare(res->phy_clk);
+	clk_disable_unprepare(res->aux_clk);
+	clk_disable_unprepare(res->ref_clk);
+	regulator_disable(res->vdda);
+@@ -472,12 +472,6 @@
+		goto err_clk_core;
+	}
+
+-	ret = clk_prepare_enable(res->phy_clk);
+-	if (ret) {
+-		dev_err(dev, "cannot prepare/enable phy clock\n");
+-		goto err_clk_phy;
+-	}
+-
+	ret = clk_prepare_enable(res->aux_clk);
+	if (ret) {
+		dev_err(dev, "cannot prepare/enable aux clock\n");
+@@ -541,6 +535,12 @@
+		return ret;
+	}
+
++	ret = clk_prepare_enable(res->phy_clk);
++	if (ret) {
++		dev_err(dev, "cannot prepare/enable phy clock\n");
++		goto err_deassert_ahb;
++	}
++
+	/* wait for clock acquisition */
+	usleep_range(1000, 1500);
+	if (pcie->force_gen1) {
+@@ -566,8 +566,6 @@
+ err_clk_ref:
+	clk_disable_unprepare(res->aux_clk);
+ err_clk_aux:
+-	clk_disable_unprepare(res->phy_clk);
+-err_clk_phy:
+	clk_disable_unprepare(res->core_clk);
+ err_clk_core:
+	clk_disable_unprepare(res->iface_clk);
diff --git a/target/linux/ipq806x/patches-4.14/0071-9-pcie-qcom-change-duplicate-pci-reset-to-phy-reset.patch b/target/linux/ipq806x/patches-4.14/0071-9-pcie-qcom-change-duplicate-pci-reset-to-phy-reset.patch
new file mode 100644
index 0000000..21cee46
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0071-9-pcie-qcom-change-duplicate-pci-reset-to-phy-reset.patch
@@ -0,0 +1,25 @@ 
+From 1a9c48123bd09f75562b6a2ee0f0a7b2d533cd45 Mon Sep 17 00:00:00 2001
+From: Abhishek Sahu <absahu@codeaurora.org>
+Date: Thu, 22 Dec 2016 11:50:49 +0530
+Subject: pcie: qcom: change duplicate pci reset to phy reset
+
+The deinit issues reset_control_assert for pci twice and
+does not contain phy reset.
+
+Change-Id: Iba849963c7e5f9a2a1063f0e2e89635df70b8a99
+Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
+---
+ drivers/pci/host/pcie-qcom.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/pci/dwc/pcie-qcom.c
++++ b/drivers/pci/dwc/pcie-qcom.c
+@@ -408,7 +408,7 @@
+	struct qcom_pcie_resources_2_1_0 *res = &pcie->res.v2_1_0;
+
+	clk_disable_unprepare(res->phy_clk);
+-	reset_control_assert(res->pci_reset);
++	reset_control_assert(res->phy_reset);
+	reset_control_assert(res->axi_reset);
+	reset_control_assert(res->ahb_reset);
+	reset_control_assert(res->por_reset);
diff --git a/target/linux/ipq806x/patches-4.14/0072-add-ipq806x-with-no-clocks.patch b/target/linux/ipq806x/patches-4.14/0072-add-ipq806x-with-no-clocks.patch
new file mode 100644
index 0000000..a29c678
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0072-add-ipq806x-with-no-clocks.patch
@@ -0,0 +1,12 @@ 
+--- a/drivers/firmware/qcom_scm.c
++++ b/drivers/firmware/qcom_scm.c
+@@ -422,6 +422,9 @@
+	{ .compatible = "qcom,scm-msm8996",
+	  .data = NULL, /* no clocks */
+	},
++	{ .compatible = "qcom,scm-ipq806x",
++	  .data = NULL, /* no clocks */
++	},
+	{ .compatible = "qcom,scm",
+	  .data = (void *)(SCM_HAS_CORE_CLK
+			   | SCM_HAS_IFACE_CLK
diff --git a/target/linux/ipq806x/patches-4.14/0073-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch b/target/linux/ipq806x/patches-4.14/0073-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch
new file mode 100644
index 0000000..89e7490
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0073-pinctrl-qom-use-scm_call-to-route-GPIO-irq-to-Apps.patch
@@ -0,0 +1,183 @@ 
+From 2034addc7e193dc81d7ca60d8884832751b76758 Mon Sep 17 00:00:00 2001
+From: Ajay Kishore <akisho@codeaurora.org>
+Date: Tue, 24 Jan 2017 14:14:16 +0530
+Subject: pinctrl: qcom: use scm_call to route GPIO irq to Apps
+
+For IPQ806x targets, TZ protects the registers that are used to
+configure the routing of interrupts to a target processor.
+To resolve this, this patch uses scm call to route GPIO interrupts
+to application processor. Also the scm call interface is changed.
+
+Change-Id: Ib6c06829d04bc8c20483c36e63da92e26cdef9ce
+Signed-off-by: Ajay Kishore <akisho@codeaurora.org>
+---
+ drivers/firmware/qcom_scm-32.c     | 17 +++++++++++++++++
+ drivers/firmware/qcom_scm-64.c     |  9 +++++++++
+ drivers/firmware/qcom_scm.c        | 13 +++++++++++++
+ drivers/firmware/qcom_scm.h        |  8 ++++++++
+ drivers/pinctrl/qcom/pinctrl-msm.c | 34 ++++++++++++++++++++++++++++------
+ include/linux/qcom_scm.h           |  3 ++-
+ 6 files changed, 77 insertions(+), 7 deletions(-)
+
+--- a/drivers/firmware/qcom_scm-32.c
++++ b/drivers/firmware/qcom_scm-32.c
+@@ -561,6 +561,24 @@
+	return ret ? : le32_to_cpu(out);
+ }
+
++int __qcom_scm_pinmux_read(u32 svc_id, u32 cmd_id, u32 arg1)
++{
++	s32 ret;
++
++	ret = qcom_scm_call_atomic1(svc_id, cmd_id, arg1);
++
++	return ret;
++}
++
++int __qcom_scm_pinmux_write(u32 svc_id, u32 cmd_id, u32 arg1, u32 arg2)
++{
++	s32 ret;
++
++	ret = qcom_scm_call_atomic2(svc_id, cmd_id, arg1, arg2);
++
++ return ret;
++}
++
+ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
+ {
+	struct {
+--- a/drivers/firmware/qcom_scm-64.c
++++ b/drivers/firmware/qcom_scm-64.c
+@@ -366,6 +366,16 @@
+	return ret ? : res.a1;
+ }
+
++int __qcom_scm_pinmux_read(u32 svc_id, u32 cmd_id, u32 arg1)
++{
++	return -ENOTSUPP;
++}
++
++int __qcom_scm_pinmux_write(u32 svc_id, u32 cmd_id, u32 arg1, u32 arg2)
++{
++	return -ENOTSUPP;
++}
++
+ int __qcom_scm_set_remote_state(struct device *dev, u32 state, u32 id)
+ {
+	struct qcom_scm_desc desc = {0};
+--- a/drivers/firmware/qcom_scm.c
++++ b/drivers/firmware/qcom_scm.c
+@@ -470,3 +470,16 @@ static int __init qcom_scm_init(void)
+	return platform_driver_register(&qcom_scm_driver);
+ }
+ subsys_initcall(qcom_scm_init);
++
++int qcom_scm_pinmux_read(u32 arg1)
++{
++	return __qcom_scm_pinmux_read(SCM_SVC_IO_ACCESS, SCM_IO_READ, arg1);
++}
++EXPORT_SYMBOL(qcom_scm_pinmux_read);
++
++int qcom_scm_pinmux_write(u32 arg1, u32 arg2)
++{
++	return __qcom_scm_pinmux_write(SCM_SVC_IO_ACCESS, SCM_IO_WRITE,
++					arg1, arg2);
++}
++EXPORT_SYMBOL(qcom_scm_pinmux_write);
+--- a/drivers/firmware/qcom_scm.h
++++ b/drivers/firmware/qcom_scm.h
+@@ -58,6 +58,13 @@ extern int  __qcom_scm_pas_auth_and_rese
+ extern int  __qcom_scm_pas_shutdown(struct device *dev, u32 peripheral);
+ extern int  __qcom_scm_pas_mss_reset(struct device *dev, bool reset);
+
++#define SCM_IO_READ	1
++#define SCM_IO_WRITE	2
++#define SCM_SVC_IO_ACCESS	0x5
++
++s32 __qcom_scm_pinmux_read(u32 svc_id, u32 cmd_id, u32 arg1);
++s32 __qcom_scm_pinmux_write(u32 svc_id, u32 cmd_id, u32 arg1, u32 arg2);
++
+ /* common error codes */
+ #define QCOM_SCM_V2_EBUSY	-12
+ #define QCOM_SCM_ENOMEM		-5
+--- a/drivers/pinctrl/qcom/pinctrl-msm.c
++++ b/drivers/pinctrl/qcom/pinctrl-msm.c
+@@ -30,7 +30,8 @@
+ #include <linux/reboot.h>
+ #include <linux/pm.h>
+ #include <linux/log2.h>
+-
++#include <linux/qcom_scm.h>
++#include <linux/io.h>
+ #include "../core.h"
+ #include "../pinconf.h"
+ #include "pinctrl-msm.h"
+@@ -638,6 +639,9 @@ static int msm_gpio_irq_set_type(struct
+	const struct msm_pingroup *g;
+	unsigned long flags;
+	u32 val;
++	u32 addr;
++	int ret;
++	const __be32 *reg;
+
+	g = &pctrl->soc->groups[d->hwirq];
+
+@@ -676,11 +680,30 @@ static int msm_gpio_irq_set_type(struct
+	else
+		clear_bit(d->hwirq, pctrl->dual_edge_irqs);
+
++	int ret = of_device_is_compatible(pctrl->dev->of_node,
++					"qcom,ipq8064-pinctrl");
+	/* Route interrupts to application cpu */
+-	val = readl(pctrl->regs + g->intr_target_reg);
+-	val &= ~(7 << g->intr_target_bit);
+-	val |= g->intr_target_kpss_val << g->intr_target_bit;
+-	writel(val, pctrl->regs + g->intr_target_reg);
++	if (!ret) {
++		val = readl(pctrl->regs + g->intr_target_reg);
++		val &= ~(7 << g->intr_target_bit);
++		val |= g->intr_target_kpss_val << g->intr_target_bit;
++		writel(val, pctrl->regs + g->intr_target_reg);
++	} else {
++		const __be32 *reg = of_get_property(pctrl->dev->of_node, "reg", NULL);
++		if (reg) {
++			u32 addr = be32_to_cpup(reg) + g->intr_target_reg;
++			val = qcom_scm_pinmux_read(addr);
++			__iormb();
++
++			val &= ~(7 << g->intr_target_bit);
++			val |= g->intr_target_kpss_val << g->intr_target_bit;
++
++			__iowmb();
++			ret = qcom_scm_pinmux_write(addr, val);
++			if (ret)
++				pr_err("\n Routing interrupts to Apps proc failed");
++		}
++	}
+
+	/* Update configuration for gpio.
+	 * RAW_STATUS_EN is left on for all gpio irqs. Due to the
+@@ -954,4 +977,3 @@ int msm_pinctrl_remove(struct platform_d
+	return 0;
+ }
+ EXPORT_SYMBOL(msm_pinctrl_remove);
+-
+--- a/include/linux/qcom_scm.h
++++ b/include/linux/qcom_scm.h
+@@ -43,6 +43,8 @@
+ extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
+ extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
+ extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
++extern s32 qcom_scm_pinmux_read(u32 arg1);
++extern s32 qcom_scm_pinmux_write(u32 arg1, u32 arg2);
+ #else
+ static inline
+ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
+@@ -73,5 +75,7 @@
+ static inline int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { return -ENODEV; }
+ static inline int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { return -ENODEV; }
+ static inline int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { return -ENODEV; }
++extern s32 qcom_scm_pinmux_read(u32 arg1) { return -ENODEV; }
++extern s32 qcom_scm_pinmux_write(u32 arg1, u32 arg2) { return -ENODEV; }
+ #endif
+ #endif
diff --git a/target/linux/ipq806x/patches-4.14/0074-ipq806x-usb-Control-USB-master-reset.patch b/target/linux/ipq806x/patches-4.14/0074-ipq806x-usb-Control-USB-master-reset.patch
new file mode 100644
index 0000000..fd208e4
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/0074-ipq806x-usb-Control-USB-master-reset.patch
@@ -0,0 +1,71 @@ 
+From a86bda9f8a7965f0cedd347a9c04800eb9f41ea3 Mon Sep 17 00:00:00 2001
+From: Vasudevan Murugesan <vmuruges@codeaurora.org>
+Date: Tue, 21 Jul 2015 10:22:38 +0530
+Subject: ipq806x: usb: Control USB master reset
+
+During removal of the glue layer(dwc3-of-simple),
+USB master reset is set to active and during insertion
+it is de-activated.
+
+Change-Id: I537dc810f6cb2a46664ee674840145066432b957
+Signed-off-by: Vasudevan Murugesan <vmuruges@codeaurora.org>
+(cherry picked from commit 4611e13580a216812f85f0801b95442d02eeb836)
+---
+ drivers/usb/dwc3/dwc3-of-simple.c | 22 ++++++++++++++++++++++
+ 1 file changed, 12 insertions(+)
+
+(limited to 'drivers/usb/dwc3/dwc3-of-simple.c')
+
+--- a/drivers/usb/dwc3/dwc3-of-simple.c
++++ b/drivers/usb/dwc3/dwc3-of-simple.c
+@@ -25,6 +25,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/clk.h>
++#include <linux/reset.h>
+ #include <linux/of.h>
+ #include <linux/of_platform.h>
+ #include <linux/pm_runtime.h>
+@@ -33,6 +34,8 @@
+	struct device		*dev;
+	struct clk		**clks;
+	int			num_clocks;
++	struct reset_control	*mstr_rst_30_0;
++	struct reset_control	*mstr_rst_30_1;
+ };
+
+ static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
+@@ -102,6 +105,20 @@
+	if (ret)
+		return ret;
+
++	simple->mstr_rst_30_0 = devm_reset_control_get(dev, "usb30_0_mstr_rst");
++
++	if (!IS_ERR(simple->mstr_rst_30_0))
++		reset_control_deassert(simple->mstr_rst_30_0);
++	else
++		dev_dbg(simple->dev, "cannot get handle for USB PHY 0 master reset control\n");
++
++	simple->mstr_rst_30_1 = devm_reset_control_get(dev, "usb30_1_mstr_rst");
++
++	if (!IS_ERR(simple->mstr_rst_30_1))
++		reset_control_deassert(simple->mstr_rst_30_1);
++	else
++		dev_dbg(simple->dev, "cannot get handle for USB PHY 1 master reset control\n");
++
+	ret = of_platform_populate(np, NULL, NULL, dev);
+	if (ret) {
+		for (i = 0; i < simple->num_clocks; i++) {
+@@ -130,6 +147,12 @@
+		clk_put(simple->clks[i]);
+	}
+
++	if (!IS_ERR(simple->mstr_rst_30_0))
++		reset_control_assert(simple->mstr_rst_30_0);
++
++	if (!IS_ERR(simple->mstr_rst_30_1))
++		reset_control_assert(simple->mstr_rst_30_1);
++
+	of_platform_depopulate(dev);
+
+	pm_runtime_put_sync(dev);
diff --git a/target/linux/ipq806x/patches-4.14/104-mtd-nand-add-Winbond-manufacturer-and-chip.patch b/target/linux/ipq806x/patches-4.14/104-mtd-nand-add-Winbond-manufacturer-and-chip.patch
new file mode 100644
index 0000000..b878147
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/104-mtd-nand-add-Winbond-manufacturer-and-chip.patch
@@ -0,0 +1,38 @@ 
+From 07b6d0cdbbda8c917480eceaec668f09e4cf24a5 Mon Sep 17 00:00:00 2001
+From: Christian Lamparter <chunkeey@gmail.com>
+Date: Mon, 14 Nov 2016 23:49:22 +0100
+Subject: [PATCH] mtd: nand: add Winbond manufacturer and chip
+
+This patch adds the W25N01GV NAND to the table of
+known devices. Without this patch the device gets detected:
+
+nand: device found, Manufacturer ID: 0xef, Chip ID: 0xaa
+nand: Unknown NAND 256MiB 1,8V 8-bit
+nand: 256 MiB, SLC, erase size: 64 KiB, page size: 1024, OOB size : 16
+
+Whereas the u-boot identifies it as:
+spi_nand: spi_nand_flash_probe SF NAND ID 00:ef:aa:21
+SF: Detected W25N01GV with page size 2 KiB, total 128 MiB
+
+Due to the page size discrepancy, it's impossible to attach
+ubi volumes on the device.
+
+Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
+---
+ drivers/mtd/nand/nand_ids.c | 4 ++++
+ include/linux/mtd/nand.h    | 1 +
+ 2 files changed, 5 insertions(+)
+
+--- a/drivers/mtd/nand/nand_ids.c
++++ b/drivers/mtd/nand/nand_ids.c
+@@ -54,6 +54,10 @@ struct nand_flash_dev nand_flash_ids[] =
+		{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
+		  SZ_8K, SZ_8K, SZ_2M, NAND_NEED_SCRAMBLING, 6, 640,
+		  NAND_ECC_INFO(40, SZ_1K), 4 },
++	{"W25N01GV 1G 3.3V 8-bit",
++		{ .id = {0xef, 0xaa} },
++		  SZ_2K, SZ_128, SZ_128K, NAND_NO_SUBPAGE_WRITE,
++		  2, 64, NAND_ECC_INFO(1, SZ_512) },
+
+	LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
+	LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
diff --git a/target/linux/ipq806x/patches-4.14/105-mtd-nor-add-mx25l25635f.patch b/target/linux/ipq806x/patches-4.14/105-mtd-nor-add-mx25l25635f.patch
new file mode 100644
index 0000000..dc9b02f
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/105-mtd-nor-add-mx25l25635f.patch
@@ -0,0 +1,22 @@ 
+Subject: mtd: spi-nor: add mx25l25635f with SECT_4K
+
+This patch fixes an issue with the creation of the
+ubi volume on the AVM FRITZ!Box 4040. The mx25l25635f
+and mx25l25635e support SECT_4K which will set the
+erase size to 4K. This is used by ubi to calculate
+VID header offsets. Without this, uboot and linux
+disagrees about the layout and refuse to attach
+the ubi volume created by the other.
+
+---
+--- a/drivers/mtd/spi-nor/spi-nor.c
++++ b/drivers/mtd/spi-nor/spi-nor.c
+@@ -1023,7 +1023,7 @@
+	{ "mx25u6435f",  INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
+	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
+-	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
++	{ "mx25l25635f", INFO(0xc22019, 0, 64 * 1024, 512, SECT_4K) },
+	{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
+	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
+	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
diff --git a/target/linux/ipq806x/patches-4.14/310-msm-adhoc-bus-support.patch b/target/linux/ipq806x/patches-4.14/310-msm-adhoc-bus-support.patch
new file mode 100644
index 0000000..56f1148
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/310-msm-adhoc-bus-support.patch
@@ -0,0 +1,11026 @@ 
+From: Christian Lamparter <chunkeey@googlemail.com>
+Subject: BUS: add MSM_BUS
+--- a/drivers/bus/Makefile
++++ b/drivers/bus/Makefile
+@@ -11,6 +11,7 @@ obj-$(CONFIG_BRCMSTB_GISB_ARB)	+= brcmst
+ obj-$(CONFIG_IMX_WEIM)		+= imx-weim.o
+ obj-$(CONFIG_MIPS_CDMM)		+= mips_cdmm.o
+ obj-$(CONFIG_MVEBU_MBUS) 	+= mvebu-mbus.o
++obj-$(CONFIG_BUS_TOPOLOGY_ADHOC)+= msm_bus/
+
+ # Interconnect bus driver for OMAP SoCs.
+ obj-$(CONFIG_OMAP_INTERCONNECT)	+= omap_l3_smx.o omap_l3_noc.o
+--- a/drivers/bus/Kconfig
++++ b/drivers/bus/Kconfig
+@@ -93,6 +93,8 @@ config MVEBU_MBUS
+	  Driver needed for the MBus configuration on Marvell EBU SoCs
+	  (Kirkwood, Dove, Orion5x, MV78XX0 and Armada 370/XP).
+
++source "drivers/bus/msm_bus/Kconfig"
++
+ config OMAP_INTERCONNECT
+	tristate "OMAP INTERCONNECT DRIVER"
+	depends on ARCH_OMAP2PLUS
+--- /dev/null
++++ b/include/dt-bindings/msm/msm-bus-ids.h
+@@ -0,0 +1,869 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __MSM_BUS_IDS_H
++#define __MSM_BUS_IDS_H
++
++/* Topology related enums */
++#define	MSM_BUS_FAB_DEFAULT 0
++#define	MSM_BUS_FAB_APPSS 0
++#define	MSM_BUS_FAB_SYSTEM 1024
++#define	MSM_BUS_FAB_MMSS 2048
++#define	MSM_BUS_FAB_SYSTEM_FPB 3072
++#define	MSM_BUS_FAB_CPSS_FPB 4096
++
++#define	MSM_BUS_FAB_BIMC 0
++#define	MSM_BUS_FAB_SYS_NOC 1024
++#define	MSM_BUS_FAB_MMSS_NOC 2048
++#define	MSM_BUS_FAB_OCMEM_NOC 3072
++#define	MSM_BUS_FAB_PERIPH_NOC 4096
++#define	MSM_BUS_FAB_CONFIG_NOC 5120
++#define	MSM_BUS_FAB_OCMEM_VNOC 6144
++#define	MSM_BUS_FAB_MMSS_AHB 2049
++#define	MSM_BUS_FAB_A0_NOC 6145
++#define	MSM_BUS_FAB_A1_NOC 6146
++#define	MSM_BUS_FAB_A2_NOC 6147
++
++#define	MSM_BUS_MASTER_FIRST 1
++#define	MSM_BUS_MASTER_AMPSS_M0 1
++#define	MSM_BUS_MASTER_AMPSS_M1 2
++#define	MSM_BUS_APPSS_MASTER_FAB_MMSS 3
++#define	MSM_BUS_APPSS_MASTER_FAB_SYSTEM 4
++#define	MSM_BUS_SYSTEM_MASTER_FAB_APPSS 5
++#define	MSM_BUS_MASTER_SPS 6
++#define	MSM_BUS_MASTER_ADM_PORT0 7
++#define	MSM_BUS_MASTER_ADM_PORT1 8
++#define	MSM_BUS_SYSTEM_MASTER_ADM1_PORT0 9
++#define	MSM_BUS_MASTER_ADM1_PORT1 10
++#define	MSM_BUS_MASTER_LPASS_PROC 11
++#define	MSM_BUS_MASTER_MSS_PROCI 12
++#define	MSM_BUS_MASTER_MSS_PROCD 13
++#define	MSM_BUS_MASTER_MSS_MDM_PORT0 14
++#define	MSM_BUS_MASTER_LPASS 15
++#define	MSM_BUS_SYSTEM_MASTER_CPSS_FPB 16
++#define	MSM_BUS_SYSTEM_MASTER_SYSTEM_FPB 17
++#define	MSM_BUS_SYSTEM_MASTER_MMSS_FPB 18
++#define	MSM_BUS_MASTER_ADM1_CI 19
++#define	MSM_BUS_MASTER_ADM0_CI 20
++#define	MSM_BUS_MASTER_MSS_MDM_PORT1 21
++#define	MSM_BUS_MASTER_MDP_PORT0 22
++#define	MSM_BUS_MASTER_MDP_PORT1 23
++#define	MSM_BUS_MMSS_MASTER_ADM1_PORT0 24
++#define	MSM_BUS_MASTER_ROTATOR 25
++#define	MSM_BUS_MASTER_GRAPHICS_3D 26
++#define	MSM_BUS_MASTER_JPEG_DEC 27
++#define	MSM_BUS_MASTER_GRAPHICS_2D_CORE0 28
++#define	MSM_BUS_MASTER_VFE 29
++#define	MSM_BUS_MASTER_VPE 30
++#define	MSM_BUS_MASTER_JPEG_ENC 31
++#define	MSM_BUS_MASTER_GRAPHICS_2D_CORE1 32
++#define	MSM_BUS_MMSS_MASTER_APPS_FAB 33
++#define	MSM_BUS_MASTER_HD_CODEC_PORT0 34
++#define	MSM_BUS_MASTER_HD_CODEC_PORT1 35
++#define	MSM_BUS_MASTER_SPDM 36
++#define	MSM_BUS_MASTER_RPM 37
++#define	MSM_BUS_MASTER_MSS 38
++#define	MSM_BUS_MASTER_RIVA 39
++#define	MSM_BUS_MASTER_SNOC_VMEM 40
++#define	MSM_BUS_MASTER_MSS_SW_PROC 41
++#define	MSM_BUS_MASTER_MSS_FW_PROC 42
++#define	MSM_BUS_MASTER_HMSS 43
++#define	MSM_BUS_MASTER_GSS_NAV 44
++#define	MSM_BUS_MASTER_PCIE 45
++#define	MSM_BUS_MASTER_SATA 46
++#define	MSM_BUS_MASTER_CRYPTO 47
++#define	MSM_BUS_MASTER_VIDEO_CAP 48
++#define	MSM_BUS_MASTER_GRAPHICS_3D_PORT1 49
++#define	MSM_BUS_MASTER_VIDEO_ENC 50
++#define	MSM_BUS_MASTER_VIDEO_DEC 51
++#define	MSM_BUS_MASTER_LPASS_AHB 52
++#define	MSM_BUS_MASTER_QDSS_BAM 53
++#define	MSM_BUS_MASTER_SNOC_CFG 54
++#define	MSM_BUS_MASTER_CRYPTO_CORE0 55
++#define	MSM_BUS_MASTER_CRYPTO_CORE1 56
++#define	MSM_BUS_MASTER_MSS_NAV 57
++#define	MSM_BUS_MASTER_OCMEM_DMA 58
++#define	MSM_BUS_MASTER_WCSS 59
++#define	MSM_BUS_MASTER_QDSS_ETR 60
++#define	MSM_BUS_MASTER_USB3 61
++#define	MSM_BUS_MASTER_JPEG 62
++#define	MSM_BUS_MASTER_VIDEO_P0 63
++#define	MSM_BUS_MASTER_VIDEO_P1 64
++#define	MSM_BUS_MASTER_MSS_PROC 65
++#define	MSM_BUS_MASTER_JPEG_OCMEM 66
++#define	MSM_BUS_MASTER_MDP_OCMEM 67
++#define	MSM_BUS_MASTER_VIDEO_P0_OCMEM 68
++#define	MSM_BUS_MASTER_VIDEO_P1_OCMEM 69
++#define	MSM_BUS_MASTER_VFE_OCMEM 70
++#define	MSM_BUS_MASTER_CNOC_ONOC_CFG 71
++#define	MSM_BUS_MASTER_RPM_INST 72
++#define	MSM_BUS_MASTER_RPM_DATA 73
++#define	MSM_BUS_MASTER_RPM_SYS 74
++#define	MSM_BUS_MASTER_DEHR 75
++#define	MSM_BUS_MASTER_QDSS_DAP 76
++#define	MSM_BUS_MASTER_TIC 77
++#define	MSM_BUS_MASTER_SDCC_1 78
++#define	MSM_BUS_MASTER_SDCC_3 79
++#define	MSM_BUS_MASTER_SDCC_4 80
++#define	MSM_BUS_MASTER_SDCC_2 81
++#define	MSM_BUS_MASTER_TSIF 82
++#define	MSM_BUS_MASTER_BAM_DMA 83
++#define	MSM_BUS_MASTER_BLSP_2 84
++#define	MSM_BUS_MASTER_USB_HSIC 85
++#define	MSM_BUS_MASTER_BLSP_1 86
++#define	MSM_BUS_MASTER_USB_HS 87
++#define	MSM_BUS_MASTER_PNOC_CFG 88
++#define	MSM_BUS_MASTER_V_OCMEM_GFX3D 89
++#define	MSM_BUS_MASTER_IPA 90
++#define	MSM_BUS_MASTER_QPIC 91
++#define	MSM_BUS_MASTER_MDPE 92
++#define	MSM_BUS_MASTER_USB_HS2 93
++#define	MSM_BUS_MASTER_VPU 94
++#define	MSM_BUS_MASTER_UFS 95
++#define	MSM_BUS_MASTER_BCAST 96
++#define	MSM_BUS_MASTER_CRYPTO_CORE2 97
++#define	MSM_BUS_MASTER_EMAC 98
++#define	MSM_BUS_MASTER_VPU_1 99
++#define	MSM_BUS_MASTER_PCIE_1 100
++#define	MSM_BUS_MASTER_USB3_1 101
++#define	MSM_BUS_MASTER_CNOC_MNOC_MMSS_CFG 102
++#define	MSM_BUS_MASTER_CNOC_MNOC_CFG 103
++#define	MSM_BUS_MASTER_TCU_0 104
++#define	MSM_BUS_MASTER_TCU_1 105
++#define	MSM_BUS_MASTER_CPP 106
++#define	MSM_BUS_MASTER_AUDIO 107
++#define	MSM_BUS_MASTER_PCIE_2 108
++#define	MSM_BUS_MASTER_BLSP_BAM 109
++#define	MSM_BUS_MASTER_USB2_BAM 110
++#define	MSM_BUS_MASTER_ADDS_DMA0 111
++#define	MSM_BUS_MASTER_ADDS_DMA1 112
++#define	MSM_BUS_MASTER_ADDS_DMA2 113
++#define	MSM_BUS_MASTER_ADDS_DMA3 114
++#define	MSM_BUS_MASTER_QPIC_BAM 115
++#define	MSM_BUS_MASTER_SDCC_BAM 116
++#define	MSM_BUS_MASTER_DDRC_SNOC 117
++#define	MSM_BUS_MASTER_WSS_0  118
++#define	MSM_BUS_MASTER_WSS_1  119
++#define	MSM_BUS_MASTER_ESS 120
++#define	MSM_BUS_MASTER_QDSS_BAMNDP 121
++#define	MSM_BUS_MASTER_QDSS_SNOC_CFG 122
++#define	MSM_BUS_MASTER_LAST 130
++
++#define	MSM_BUS_SYSTEM_FPB_MASTER_SYSTEM MSM_BUS_SYSTEM_MASTER_SYSTEM_FPB
++#define	MSM_BUS_CPSS_FPB_MASTER_SYSTEM MSM_BUS_SYSTEM_MASTER_CPSS_FPB
++
++#define	MSM_BUS_SNOC_MM_INT_0 10000
++#define	MSM_BUS_SNOC_MM_INT_1 10001
++#define	MSM_BUS_SNOC_MM_INT_2 10002
++#define	MSM_BUS_SNOC_MM_INT_BIMC 10003
++#define	MSM_BUS_SNOC_INT_0 10004
++#define	MSM_BUS_SNOC_INT_1 10005
++#define	MSM_BUS_SNOC_INT_BIMC 10006
++#define	MSM_BUS_SNOC_BIMC_0_MAS 10007
++#define	MSM_BUS_SNOC_BIMC_1_MAS 10008
++#define	MSM_BUS_SNOC_QDSS_INT 10009
++#define	MSM_BUS_PNOC_SNOC_MAS 10010
++#define	MSM_BUS_PNOC_SNOC_SLV 10011
++#define	MSM_BUS_PNOC_INT_0 10012
++#define	MSM_BUS_PNOC_INT_1 10013
++#define	MSM_BUS_PNOC_M_0 10014
++#define	MSM_BUS_PNOC_M_1 10015
++#define	MSM_BUS_BIMC_SNOC_MAS 10016
++#define	MSM_BUS_BIMC_SNOC_SLV 10017
++#define	MSM_BUS_PNOC_SLV_0 10018
++#define	MSM_BUS_PNOC_SLV_1 10019
++#define	MSM_BUS_PNOC_SLV_2 10020
++#define	MSM_BUS_PNOC_SLV_3 10021
++#define	MSM_BUS_PNOC_SLV_4 10022
++#define	MSM_BUS_PNOC_SLV_8 10023
++#define	MSM_BUS_PNOC_SLV_9 10024
++#define	MSM_BUS_SNOC_BIMC_0_SLV 10025
++#define	MSM_BUS_SNOC_BIMC_1_SLV 10026
++#define	MSM_BUS_MNOC_BIMC_MAS 10027
++#define	MSM_BUS_MNOC_BIMC_SLV 10028
++#define	MSM_BUS_BIMC_MNOC_MAS 10029
++#define	MSM_BUS_BIMC_MNOC_SLV 10030
++#define	MSM_BUS_SNOC_BIMC_MAS 10031
++#define	MSM_BUS_SNOC_BIMC_SLV 10032
++#define	MSM_BUS_CNOC_SNOC_MAS 10033
++#define	MSM_BUS_CNOC_SNOC_SLV 10034
++#define	MSM_BUS_SNOC_CNOC_MAS 10035
++#define	MSM_BUS_SNOC_CNOC_SLV 10036
++#define	MSM_BUS_OVNOC_SNOC_MAS 10037
++#define	MSM_BUS_OVNOC_SNOC_SLV 10038
++#define	MSM_BUS_SNOC_OVNOC_MAS 10039
++#define	MSM_BUS_SNOC_OVNOC_SLV 10040
++#define	MSM_BUS_SNOC_PNOC_MAS 10041
++#define	MSM_BUS_SNOC_PNOC_SLV 10042
++#define	MSM_BUS_BIMC_INT_APPS_EBI 10043
++#define	MSM_BUS_BIMC_INT_APPS_SNOC 10044
++#define	MSM_BUS_SNOC_BIMC_2_MAS 10045
++#define	MSM_BUS_SNOC_BIMC_2_SLV 10046
++#define	MSM_BUS_PNOC_SLV_5 10047
++#define	MSM_BUS_PNOC_SLV_6 10048
++#define	MSM_BUS_PNOC_INT_2 10049
++#define	MSM_BUS_PNOC_INT_3 10050
++#define	MSM_BUS_PNOC_INT_4 10051
++#define	MSM_BUS_PNOC_INT_5 10052
++#define	MSM_BUS_PNOC_INT_6 10053
++#define	MSM_BUS_PNOC_INT_7 10054
++#define	MSM_BUS_BIMC_SNOC_1_MAS 10055
++#define	MSM_BUS_BIMC_SNOC_1_SLV 10056
++#define	MSM_BUS_PNOC_A1NOC_MAS 10057
++#define	MSM_BUS_PNOC_A1NOC_SLV 10058
++#define	MSM_BUS_CNOC_A1NOC_MAS 10059
++#define	MSM_BUS_A0NOC_SNOC_MAS 10060
++#define	MSM_BUS_A0NOC_SNOC_SLV 10061
++#define	MSM_BUS_A1NOC_SNOC_SLV 10062
++#define	MSM_BUS_A1NOC_SNOC_MAS 10063
++#define	MSM_BUS_A2NOC_SNOC_MAS 10064
++#define	MSM_BUS_A2NOC_SNOC_SLV 10065
++#define	MSM_BUS_PNOC_SLV_7 10066
++#define	MSM_BUS_INT_LAST 10067
++
++#define	MSM_BUS_SLAVE_FIRST 512
++#define	MSM_BUS_SLAVE_EBI_CH0 512
++#define	MSM_BUS_SLAVE_EBI_CH1 513
++#define	MSM_BUS_SLAVE_AMPSS_L2 514
++#define	MSM_BUS_APPSS_SLAVE_FAB_MMSS 515
++#define	MSM_BUS_APPSS_SLAVE_FAB_SYSTEM 516
++#define	MSM_BUS_SYSTEM_SLAVE_FAB_APPS 517
++#define	MSM_BUS_SLAVE_SPS 518
++#define	MSM_BUS_SLAVE_SYSTEM_IMEM 519
++#define	MSM_BUS_SLAVE_AMPSS 520
++#define	MSM_BUS_SLAVE_MSS 521
++#define	MSM_BUS_SLAVE_LPASS 522
++#define	MSM_BUS_SYSTEM_SLAVE_CPSS_FPB 523
++#define	MSM_BUS_SYSTEM_SLAVE_SYSTEM_FPB 524
++#define	MSM_BUS_SYSTEM_SLAVE_MMSS_FPB 525
++#define	MSM_BUS_SLAVE_CORESIGHT 526
++#define	MSM_BUS_SLAVE_RIVA 527
++#define	MSM_BUS_SLAVE_SMI 528
++#define	MSM_BUS_MMSS_SLAVE_FAB_APPS 529
++#define	MSM_BUS_MMSS_SLAVE_FAB_APPS_1 530
++#define	MSM_BUS_SLAVE_MM_IMEM 531
++#define	MSM_BUS_SLAVE_CRYPTO 532
++#define	MSM_BUS_SLAVE_SPDM 533
++#define	MSM_BUS_SLAVE_RPM 534
++#define	MSM_BUS_SLAVE_RPM_MSG_RAM 535
++#define	MSM_BUS_SLAVE_MPM 536
++#define	MSM_BUS_SLAVE_PMIC1_SSBI1_A 537
++#define	MSM_BUS_SLAVE_PMIC1_SSBI1_B 538
++#define	MSM_BUS_SLAVE_PMIC1_SSBI1_C 539
++#define	MSM_BUS_SLAVE_PMIC2_SSBI2_A 540
++#define	MSM_BUS_SLAVE_PMIC2_SSBI2_B 541
++#define	MSM_BUS_SLAVE_GSBI1_UART 542
++#define	MSM_BUS_SLAVE_GSBI2_UART 543
++#define	MSM_BUS_SLAVE_GSBI3_UART 544
++#define	MSM_BUS_SLAVE_GSBI4_UART 545
++#define	MSM_BUS_SLAVE_GSBI5_UART 546
++#define	MSM_BUS_SLAVE_GSBI6_UART 547
++#define	MSM_BUS_SLAVE_GSBI7_UART 548
++#define	MSM_BUS_SLAVE_GSBI8_UART 549
++#define	MSM_BUS_SLAVE_GSBI9_UART 550
++#define	MSM_BUS_SLAVE_GSBI10_UART 551
++#define	MSM_BUS_SLAVE_GSBI11_UART 552
++#define	MSM_BUS_SLAVE_GSBI12_UART 553
++#define	MSM_BUS_SLAVE_GSBI1_QUP 554
++#define	MSM_BUS_SLAVE_GSBI2_QUP 555
++#define	MSM_BUS_SLAVE_GSBI3_QUP 556
++#define	MSM_BUS_SLAVE_GSBI4_QUP 557
++#define	MSM_BUS_SLAVE_GSBI5_QUP 558
++#define	MSM_BUS_SLAVE_GSBI6_QUP 559
++#define	MSM_BUS_SLAVE_GSBI7_QUP 560
++#define	MSM_BUS_SLAVE_GSBI8_QUP 561
++#define	MSM_BUS_SLAVE_GSBI9_QUP 562
++#define	MSM_BUS_SLAVE_GSBI10_QUP 563
++#define	MSM_BUS_SLAVE_GSBI11_QUP 564
++#define	MSM_BUS_SLAVE_GSBI12_QUP 565
++#define	MSM_BUS_SLAVE_EBI2_NAND 566
++#define	MSM_BUS_SLAVE_EBI2_CS0 567
++#define	MSM_BUS_SLAVE_EBI2_CS1 568
++#define	MSM_BUS_SLAVE_EBI2_CS2 569
++#define	MSM_BUS_SLAVE_EBI2_CS3 570
++#define	MSM_BUS_SLAVE_EBI2_CS4 571
++#define	MSM_BUS_SLAVE_EBI2_CS5 572
++#define	MSM_BUS_SLAVE_USB_FS1 573
++#define	MSM_BUS_SLAVE_USB_FS2 574
++#define	MSM_BUS_SLAVE_TSIF 575
++#define	MSM_BUS_SLAVE_MSM_TSSC 576
++#define	MSM_BUS_SLAVE_MSM_PDM 577
++#define	MSM_BUS_SLAVE_MSM_DIMEM 578
++#define	MSM_BUS_SLAVE_MSM_TCSR 579
++#define	MSM_BUS_SLAVE_MSM_PRNG 580
++#define	MSM_BUS_SLAVE_GSS 581
++#define	MSM_BUS_SLAVE_SATA 582
++#define	MSM_BUS_SLAVE_USB3 583
++#define	MSM_BUS_SLAVE_WCSS 584
++#define	MSM_BUS_SLAVE_OCIMEM 585
++#define	MSM_BUS_SLAVE_SNOC_OCMEM 586
++#define	MSM_BUS_SLAVE_SERVICE_SNOC 587
++#define	MSM_BUS_SLAVE_QDSS_STM 588
++#define	MSM_BUS_SLAVE_CAMERA_CFG 589
++#define	MSM_BUS_SLAVE_DISPLAY_CFG 590
++#define	MSM_BUS_SLAVE_OCMEM_CFG 591
++#define	MSM_BUS_SLAVE_CPR_CFG 592
++#define	MSM_BUS_SLAVE_CPR_XPU_CFG 593
++#define	MSM_BUS_SLAVE_MISC_CFG 594
++#define	MSM_BUS_SLAVE_MISC_XPU_CFG 595
++#define	MSM_BUS_SLAVE_VENUS_CFG 596
++#define	MSM_BUS_SLAVE_MISC_VENUS_CFG 597
++#define	MSM_BUS_SLAVE_GRAPHICS_3D_CFG 598
++#define	MSM_BUS_SLAVE_MMSS_CLK_CFG 599
++#define	MSM_BUS_SLAVE_MMSS_CLK_XPU_CFG 600
++#define	MSM_BUS_SLAVE_MNOC_MPU_CFG 601
++#define	MSM_BUS_SLAVE_ONOC_MPU_CFG 602
++#define	MSM_BUS_SLAVE_SERVICE_MNOC 603
++#define	MSM_BUS_SLAVE_OCMEM 604
++#define	MSM_BUS_SLAVE_SERVICE_ONOC 605
++#define	MSM_BUS_SLAVE_SDCC_1 606
++#define	MSM_BUS_SLAVE_SDCC_3 607
++#define	MSM_BUS_SLAVE_SDCC_2 608
++#define	MSM_BUS_SLAVE_SDCC_4 609
++#define	MSM_BUS_SLAVE_BAM_DMA 610
++#define	MSM_BUS_SLAVE_BLSP_2 611
++#define	MSM_BUS_SLAVE_USB_HSIC 612
++#define	MSM_BUS_SLAVE_BLSP_1 613
++#define	MSM_BUS_SLAVE_USB_HS 614
++#define	MSM_BUS_SLAVE_PDM 615
++#define	MSM_BUS_SLAVE_PERIPH_APU_CFG 616
++#define	MSM_BUS_SLAVE_PNOC_MPU_CFG 617
++#define	MSM_BUS_SLAVE_PRNG 618
++#define	MSM_BUS_SLAVE_SERVICE_PNOC 619
++#define	MSM_BUS_SLAVE_CLK_CTL 620
++#define	MSM_BUS_SLAVE_CNOC_MSS 621
++#define	MSM_BUS_SLAVE_SECURITY 622
++#define	MSM_BUS_SLAVE_TCSR 623
++#define	MSM_BUS_SLAVE_TLMM 624
++#define	MSM_BUS_SLAVE_CRYPTO_0_CFG 625
++#define	MSM_BUS_SLAVE_CRYPTO_1_CFG 626
++#define	MSM_BUS_SLAVE_IMEM_CFG 627
++#define	MSM_BUS_SLAVE_MESSAGE_RAM 628
++#define	MSM_BUS_SLAVE_BIMC_CFG 629
++#define	MSM_BUS_SLAVE_BOOT_ROM 630
++#define	MSM_BUS_SLAVE_CNOC_MNOC_MMSS_CFG 631
++#define	MSM_BUS_SLAVE_PMIC_ARB 632
++#define	MSM_BUS_SLAVE_SPDM_WRAPPER 633
++#define	MSM_BUS_SLAVE_DEHR_CFG 634
++#define	MSM_BUS_SLAVE_QDSS_CFG 635
++#define	MSM_BUS_SLAVE_RBCPR_CFG 636
++#define	MSM_BUS_SLAVE_RBCPR_QDSS_APU_CFG 637
++#define	MSM_BUS_SLAVE_SNOC_MPU_CFG 638
++#define	MSM_BUS_SLAVE_CNOC_ONOC_CFG 639
++#define	MSM_BUS_SLAVE_CNOC_MNOC_CFG 640
++#define	MSM_BUS_SLAVE_PNOC_CFG 641
++#define	MSM_BUS_SLAVE_SNOC_CFG 642
++#define	MSM_BUS_SLAVE_EBI1_DLL_CFG 643
++#define	MSM_BUS_SLAVE_PHY_APU_CFG 644
++#define	MSM_BUS_SLAVE_EBI1_PHY_CFG 645
++#define	MSM_BUS_SLAVE_SERVICE_CNOC 646
++#define	MSM_BUS_SLAVE_IPS_CFG 647
++#define	MSM_BUS_SLAVE_QPIC 648
++#define	MSM_BUS_SLAVE_DSI_CFG 649
++#define	MSM_BUS_SLAVE_UFS_CFG 650
++#define	MSM_BUS_SLAVE_RBCPR_CX_CFG 651
++#define	MSM_BUS_SLAVE_RBCPR_MX_CFG 652
++#define	MSM_BUS_SLAVE_PCIE_CFG 653
++#define	MSM_BUS_SLAVE_USB_PHYS_CFG 654
++#define	MSM_BUS_SLAVE_VIDEO_CAP_CFG 655
++#define	MSM_BUS_SLAVE_AVSYNC_CFG 656
++#define	MSM_BUS_SLAVE_CRYPTO_2_CFG 657
++#define	MSM_BUS_SLAVE_VPU_CFG 658
++#define	MSM_BUS_SLAVE_BCAST_CFG 659
++#define	MSM_BUS_SLAVE_KLM_CFG 660
++#define	MSM_BUS_SLAVE_GENI_IR_CFG 661
++#define	MSM_BUS_SLAVE_OCMEM_GFX 662
++#define	MSM_BUS_SLAVE_CATS_128 663
++#define	MSM_BUS_SLAVE_OCMEM_64 664
++#define MSM_BUS_SLAVE_PCIE_0 665
++#define MSM_BUS_SLAVE_PCIE_1 666
++#define	MSM_BUS_SLAVE_PCIE_0_CFG 667
++#define	MSM_BUS_SLAVE_PCIE_1_CFG 668
++#define	MSM_BUS_SLAVE_SRVC_MNOC 669
++#define	MSM_BUS_SLAVE_USB_HS2 670
++#define	MSM_BUS_SLAVE_AUDIO	671
++#define	MSM_BUS_SLAVE_TCU	672
++#define	MSM_BUS_SLAVE_APPSS	673
++#define	MSM_BUS_SLAVE_PCIE_PARF	674
++#define	MSM_BUS_SLAVE_USB3_PHY_CFG	675
++#define	MSM_BUS_SLAVE_IPA_CFG	676
++#define	MSM_BUS_SLAVE_A0NOC_SNOC 677
++#define	MSM_BUS_SLAVE_A1NOC_SNOC 678
++#define	MSM_BUS_SLAVE_A2NOC_SNOC 679
++#define	MSM_BUS_SLAVE_HMSS_L3 680
++#define	MSM_BUS_SLAVE_PIMEM_CFG 681
++#define	MSM_BUS_SLAVE_DCC_CFG 682
++#define	MSM_BUS_SLAVE_QDSS_RBCPR_APU_CFG 683
++#define	MSM_BUS_SLAVE_PCIE_2_CFG 684
++#define	MSM_BUS_SLAVE_PCIE20_AHB2PHY 685
++#define	MSM_BUS_SLAVE_A0NOC_CFG 686
++#define	MSM_BUS_SLAVE_A1NOC_CFG 687
++#define	MSM_BUS_SLAVE_A2NOC_CFG 688
++#define	MSM_BUS_SLAVE_A1NOC_MPU_CFG 689
++#define	MSM_BUS_SLAVE_A2NOC_MPU_CFG 690
++#define	MSM_BUS_SLAVE_A0NOC_SMMU_CFG 691
++#define	MSM_BUS_SLAVE_A1NOC_SMMU_CFG 692
++#define	MSM_BUS_SLAVE_A2NOC_SMMU_CFG 693
++#define	MSM_BUS_SLAVE_LPASS_SMMU_CFG 694
++#define	MSM_BUS_SLAVE_MMAGIC_CFG 695
++#define	MSM_BUS_SLAVE_VENUS_THROTTLE_CFG 696
++#define	MSM_BUS_SLAVE_SSC_CFG 697
++#define	MSM_BUS_SLAVE_DSA_CFG 698
++#define	MSM_BUS_SLAVE_DSA_MPU_CFG 699
++#define	MSM_BUS_SLAVE_DISPLAY_THROTTLE_CFG 700
++#define	MSM_BUS_SLAVE_SMMU_CPP_CFG 701
++#define	MSM_BUS_SLAVE_SMMU_JPEG_CFG 702
++#define	MSM_BUS_SLAVE_SMMU_MDP_CFG 703
++#define	MSM_BUS_SLAVE_SMMU_ROTATOR_CFG 704
++#define	MSM_BUS_SLAVE_SMMU_VENUS_CFG 705
++#define	MSM_BUS_SLAVE_SMMU_VFE_CFG 706
++#define	MSM_BUS_SLAVE_A0NOC_MPU_CFG 707
++#define	MSM_BUS_SLAVE_VMEM_CFG 708
++#define	MSM_BUS_SLAVE_CAMERA_THROTTLE_CFG 700
++#define	MSM_BUS_SLAVE_VMEM 709
++#define	MSM_BUS_SLAVE_AHB2PHY 710
++#define	MSM_BUS_SLAVE_PIMEM 711
++#define	MSM_BUS_SLAVE_SNOC_VMEM 712
++#define	MSM_BUS_SLAVE_PCIE_2 713
++#define	MSM_BUS_SLAVE_RBCPR_MX 714
++#define	MSM_BUS_SLAVE_RBCPR_CX 715
++#define	MSM_BUS_SLAVE_PRNG_APU_CFG 716
++#define	MSM_BUS_SLAVE_PERIPH_MPU_CFG 717
++#define	MSM_BUS_SLAVE_GCNT 718
++#define	MSM_BUS_SLAVE_ADSS_CFG 719
++#define	MSM_BUS_SLAVE_ADSS_VMIDMT_CFG 720
++#define	MSM_BUS_SLAVE_QHSS_APU_CFG 721
++#define	MSM_BUS_SLAVE_MDIO 722
++#define	MSM_BUS_SLAVE_FEPHY_CFG 723
++#define	MSM_BUS_SLAVE_SRIF 724
++#define	MSM_BUS_SLAVE_LAST 730
++#define	MSM_BUS_SLAVE_DDRC_CFG 731
++#define	MSM_BUS_SLAVE_DDRC_APU_CFG 732
++#define	MSM_BUS_SLAVE_MPU0_CFG 733
++#define	MSM_BUS_SLAVE_MPU1_CFG 734
++#define	MSM_BUS_SLAVE_MPU2_CFG 734
++#define	MSM_BUS_SLAVE_ESS_VMIDMT_CFG 735
++#define	MSM_BUS_SLAVE_ESS_APU_CFG 736
++#define	MSM_BUS_SLAVE_USB2_CFG 737
++#define	MSM_BUS_SLAVE_BLSP_CFG 738
++#define	MSM_BUS_SLAVE_QPIC_CFG 739
++#define	MSM_BUS_SLAVE_SDCC_CFG 740
++#define	MSM_BUS_SLAVE_WSS0_VMIDMT_CFG 741
++#define	MSM_BUS_SLAVE_WSS0_APU_CFG 742
++#define	MSM_BUS_SLAVE_WSS1_VMIDMT_CFG 743
++#define	MSM_BUS_SLAVE_WSS1_APU_CFG 744
++#define	MSM_BUS_SLAVE_SRVC_PCNOC 745
++#define	MSM_BUS_SLAVE_SNOC_DDRC 746
++#define	MSM_BUS_SLAVE_A7SS 747
++#define	MSM_BUS_SLAVE_WSS0_CFG 748
++#define	MSM_BUS_SLAVE_WSS1_CFG 749
++#define	MSM_BUS_SLAVE_PCIE 750
++#define	MSM_BUS_SLAVE_USB3_CFG 751
++#define	MSM_BUS_SLAVE_CRYPTO_CFG 752
++#define	MSM_BUS_SLAVE_ESS_CFG 753
++#define	MSM_BUS_SLAVE_SRVC_SNOC 754
++
++#define	MSM_BUS_SYSTEM_FPB_SLAVE_SYSTEM  MSM_BUS_SYSTEM_SLAVE_SYSTEM_FPB
++#define MSM_BUS_CPSS_FPB_SLAVE_SYSTEM MSM_BUS_SYSTEM_SLAVE_CPSS_FPB
++
++/*
++ * ID's used in RPM messages
++ */
++#define ICBID_MASTER_APPSS_PROC 0
++#define ICBID_MASTER_MSS_PROC 1
++#define ICBID_MASTER_MNOC_BIMC 2
++#define ICBID_MASTER_SNOC_BIMC 3
++#define ICBID_MASTER_SNOC_BIMC_0 ICBID_MASTER_SNOC_BIMC
++#define ICBID_MASTER_CNOC_MNOC_MMSS_CFG 4
++#define ICBID_MASTER_CNOC_MNOC_CFG 5
++#define ICBID_MASTER_GFX3D 6
++#define ICBID_MASTER_JPEG 7
++#define ICBID_MASTER_MDP 8
++#define ICBID_MASTER_MDP0 ICBID_MASTER_MDP
++#define ICBID_MASTER_MDPS ICBID_MASTER_MDP
++#define ICBID_MASTER_VIDEO 9
++#define ICBID_MASTER_VIDEO_P0 ICBID_MASTER_VIDEO
++#define ICBID_MASTER_VIDEO_P1 10
++#define ICBID_MASTER_VFE 11
++#define ICBID_MASTER_CNOC_ONOC_CFG 12
++#define ICBID_MASTER_JPEG_OCMEM 13
++#define ICBID_MASTER_MDP_OCMEM 14
++#define ICBID_MASTER_VIDEO_P0_OCMEM 15
++#define ICBID_MASTER_VIDEO_P1_OCMEM 16
++#define ICBID_MASTER_VFE_OCMEM 17
++#define ICBID_MASTER_LPASS_AHB 18
++#define ICBID_MASTER_QDSS_BAM 19
++#define ICBID_MASTER_SNOC_CFG 20
++#define ICBID_MASTER_BIMC_SNOC 21
++#define ICBID_MASTER_CNOC_SNOC 22
++#define ICBID_MASTER_CRYPTO 23
++#define ICBID_MASTER_CRYPTO_CORE0 ICBID_MASTER_CRYPTO
++#define ICBID_MASTER_CRYPTO_CORE1 24
++#define ICBID_MASTER_LPASS_PROC 25
++#define ICBID_MASTER_MSS 26
++#define ICBID_MASTER_MSS_NAV 27
++#define ICBID_MASTER_OCMEM_DMA 28
++#define ICBID_MASTER_PNOC_SNOC 29
++#define ICBID_MASTER_WCSS 30
++#define ICBID_MASTER_QDSS_ETR 31
++#define ICBID_MASTER_USB3 32
++#define ICBID_MASTER_USB3_0 ICBID_MASTER_USB3
++#define ICBID_MASTER_SDCC_1 33
++#define ICBID_MASTER_SDCC_3 34
++#define ICBID_MASTER_SDCC_2 35
++#define ICBID_MASTER_SDCC_4 36
++#define ICBID_MASTER_TSIF 37
++#define ICBID_MASTER_BAM_DMA 38
++#define ICBID_MASTER_BLSP_2 39
++#define ICBID_MASTER_USB_HSIC 40
++#define ICBID_MASTER_BLSP_1 41
++#define ICBID_MASTER_USB_HS 42
++#define ICBID_MASTER_USB_HS1 ICBID_MASTER_USB_HS
++#define ICBID_MASTER_PNOC_CFG 43
++#define ICBID_MASTER_SNOC_PNOC 44
++#define ICBID_MASTER_RPM_INST 45
++#define ICBID_MASTER_RPM_DATA 46
++#define ICBID_MASTER_RPM_SYS 47
++#define ICBID_MASTER_DEHR 48
++#define ICBID_MASTER_QDSS_DAP 49
++#define ICBID_MASTER_SPDM 50
++#define ICBID_MASTER_TIC 51
++#define ICBID_MASTER_SNOC_CNOC 52
++#define ICBID_MASTER_GFX3D_OCMEM 53
++#define ICBID_MASTER_GFX3D_GMEM ICBID_MASTER_GFX3D_OCMEM
++#define ICBID_MASTER_OVIRT_SNOC 54
++#define ICBID_MASTER_SNOC_OVIRT 55
++#define ICBID_MASTER_SNOC_GVIRT ICBID_MASTER_SNOC_OVIRT
++#define ICBID_MASTER_ONOC_OVIRT 56
++#define ICBID_MASTER_USB_HS2 57
++#define ICBID_MASTER_QPIC 58
++#define ICBID_MASTER_IPA 59
++#define ICBID_MASTER_DSI 60
++#define ICBID_MASTER_MDP1 61
++#define ICBID_MASTER_MDPE ICBID_MASTER_MDP1
++#define ICBID_MASTER_VPU_PROC 62
++#define ICBID_MASTER_VPU 63
++#define ICBID_MASTER_VPU0 ICBID_MASTER_VPU
++#define ICBID_MASTER_CRYPTO_CORE2 64
++#define ICBID_MASTER_PCIE_0 65
++#define ICBID_MASTER_PCIE_1 66
++#define ICBID_MASTER_SATA 67
++#define ICBID_MASTER_UFS 68
++#define ICBID_MASTER_USB3_1 69
++#define ICBID_MASTER_VIDEO_OCMEM 70
++#define ICBID_MASTER_VPU1 71
++#define ICBID_MASTER_VCAP 72
++#define ICBID_MASTER_EMAC 73
++#define ICBID_MASTER_BCAST 74
++#define ICBID_MASTER_MMSS_PROC 75
++#define ICBID_MASTER_SNOC_BIMC_1 76
++#define ICBID_MASTER_SNOC_PCNOC 77
++#define ICBID_MASTER_AUDIO 78
++#define ICBID_MASTER_MM_INT_0 79
++#define ICBID_MASTER_MM_INT_1 80
++#define ICBID_MASTER_MM_INT_2 81
++#define ICBID_MASTER_MM_INT_BIMC 82
++#define ICBID_MASTER_MSS_INT 83
++#define ICBID_MASTER_PCNOC_CFG 84
++#define ICBID_MASTER_PCNOC_INT_0 85
++#define ICBID_MASTER_PCNOC_INT_1 86
++#define ICBID_MASTER_PCNOC_M_0 87
++#define ICBID_MASTER_PCNOC_M_1 88
++#define ICBID_MASTER_PCNOC_S_0 89
++#define ICBID_MASTER_PCNOC_S_1 90
++#define ICBID_MASTER_PCNOC_S_2 91
++#define ICBID_MASTER_PCNOC_S_3 92
++#define ICBID_MASTER_PCNOC_S_4 93
++#define ICBID_MASTER_PCNOC_S_6 94
++#define ICBID_MASTER_PCNOC_S_7 95
++#define ICBID_MASTER_PCNOC_S_8 96
++#define ICBID_MASTER_PCNOC_S_9 97
++#define ICBID_MASTER_QDSS_INT 98
++#define ICBID_MASTER_SNOC_INT_0 99
++#define ICBID_MASTER_SNOC_INT_1 100
++#define ICBID_MASTER_SNOC_INT_BIMC 101
++#define ICBID_MASTER_TCU_0 102
++#define ICBID_MASTER_TCU_1 103
++#define ICBID_MASTER_BIMC_INT_0 104
++#define ICBID_MASTER_BIMC_INT_1 105
++#define ICBID_MASTER_CAMERA 106
++#define ICBID_MASTER_RICA 107
++#define ICBID_MASTER_PCNOC_S_5	129
++#define ICBID_MASTER_PCNOC_INT_2	124
++#define ICBID_MASTER_PCNOC_INT_3	125
++#define ICBID_MASTER_PCNOC_INT_4	126
++#define ICBID_MASTER_PCNOC_INT_5	127
++#define ICBID_MASTER_PCNOC_INT_6	128
++#define ICBID_MASTER_PCIE_2 119
++#define ICBID_MASTER_MASTER_CNOC_A1NOC 116
++#define ICBID_MASTER_A0NOC_SNOC 110
++#define ICBID_MASTER_A1NOC_SNOC 111
++#define ICBID_MASTER_A2NOC_SNOC 112
++#define ICBID_MASTER_PNOC_A1NOC 117
++#define ICBID_MASTER_ROTATOR 120
++#define ICBID_MASTER_SNOC_VMEM 114
++#define ICBID_MASTER_VENUS_VMEM 121
++#define ICBID_MASTER_HMSS 118
++#define ICBID_MASTER_BIMC_SNOC_1 109
++#define ICBID_MASTER_CNOC_A1NOC 116
++#define ICBID_MASTER_CPP 115
++#define ICBID_MASTER_BLSP_BAM 130
++#define ICBID_MASTER_USB2_BAM 131
++#define ICBID_MASTER_ADSS_DMA0 132
++#define ICBID_MASTER_ADSS_DMA1 133
++#define ICBID_MASTER_ADSS_DMA2 134
++#define ICBID_MASTER_ADSS_DMA3 135
++#define ICBID_MASTER_QPIC_BAM 136
++#define ICBID_MASTER_SDCC_BAM 137
++#define ICBID_MASTER_DDRC_SNOC 138
++#define ICBID_MASTER_WSS_0 139
++#define ICBID_MASTER_WSS_1 140
++#define ICBID_MASTER_ESS 141
++#define ICBID_MASTER_PCIE 142
++#define ICBID_MASTER_QDSS_BAMNDP 143
++#define ICBID_MASTER_QDSS_SNOC_CFG 144
++
++#define ICBID_SLAVE_EBI1 0
++#define ICBID_SLAVE_APPSS_L2 1
++#define ICBID_SLAVE_BIMC_SNOC 2
++#define ICBID_SLAVE_CAMERA_CFG 3
++#define ICBID_SLAVE_DISPLAY_CFG 4
++#define ICBID_SLAVE_OCMEM_CFG 5
++#define ICBID_SLAVE_CPR_CFG 6
++#define ICBID_SLAVE_CPR_XPU_CFG 7
++#define ICBID_SLAVE_MISC_CFG 8
++#define ICBID_SLAVE_MISC_XPU_CFG 9
++#define ICBID_SLAVE_VENUS_CFG 10
++#define ICBID_SLAVE_GFX3D_CFG 11
++#define ICBID_SLAVE_MMSS_CLK_CFG 12
++#define ICBID_SLAVE_MMSS_CLK_XPU_CFG 13
++#define ICBID_SLAVE_MNOC_MPU_CFG 14
++#define ICBID_SLAVE_ONOC_MPU_CFG 15
++#define ICBID_SLAVE_MNOC_BIMC 16
++#define ICBID_SLAVE_SERVICE_MNOC 17
++#define ICBID_SLAVE_OCMEM 18
++#define ICBID_SLAVE_GMEM ICBID_SLAVE_OCMEM
++#define ICBID_SLAVE_SERVICE_ONOC 19
++#define ICBID_SLAVE_APPSS 20
++#define ICBID_SLAVE_LPASS 21
++#define ICBID_SLAVE_USB3 22
++#define ICBID_SLAVE_USB3_0 ICBID_SLAVE_USB3
++#define ICBID_SLAVE_WCSS 23
++#define ICBID_SLAVE_SNOC_BIMC 24
++#define ICBID_SLAVE_SNOC_BIMC_0 ICBID_SLAVE_SNOC_BIMC
++#define ICBID_SLAVE_SNOC_CNOC 25
++#define ICBID_SLAVE_IMEM 26
++#define ICBID_SLAVE_OCIMEM ICBID_SLAVE_IMEM
++#define ICBID_SLAVE_SNOC_OVIRT 27
++#define ICBID_SLAVE_SNOC_GVIRT ICBID_SLAVE_SNOC_OVIRT
++#define ICBID_SLAVE_SNOC_PNOC 28
++#define ICBID_SLAVE_SNOC_PCNOC ICBID_SLAVE_SNOC_PNOC
++#define ICBID_SLAVE_SERVICE_SNOC 29
++#define ICBID_SLAVE_QDSS_STM 30
++#define ICBID_SLAVE_SDCC_1 31
++#define ICBID_SLAVE_SDCC_3 32
++#define ICBID_SLAVE_SDCC_2 33
++#define ICBID_SLAVE_SDCC_4 34
++#define ICBID_SLAVE_TSIF 35
++#define ICBID_SLAVE_BAM_DMA 36
++#define ICBID_SLAVE_BLSP_2 37
++#define ICBID_SLAVE_USB_HSIC 38
++#define ICBID_SLAVE_BLSP_1 39
++#define ICBID_SLAVE_USB_HS 40
++#define ICBID_SLAVE_USB_HS1 ICBID_SLAVE_USB_HS
++#define ICBID_SLAVE_PDM 41
++#define ICBID_SLAVE_PERIPH_APU_CFG 42
++#define ICBID_SLAVE_PNOC_MPU_CFG 43
++#define ICBID_SLAVE_PRNG 44
++#define ICBID_SLAVE_PNOC_SNOC 45
++#define ICBID_SLAVE_PCNOC_SNOC ICBID_SLAVE_PNOC_SNOC
++#define ICBID_SLAVE_SERVICE_PNOC 46
++#define ICBID_SLAVE_CLK_CTL 47
++#define ICBID_SLAVE_CNOC_MSS 48
++#define ICBID_SLAVE_PCNOC_MSS ICBID_SLAVE_CNOC_MSS
++#define ICBID_SLAVE_SECURITY 49
++#define ICBID_SLAVE_TCSR 50
++#define ICBID_SLAVE_TLMM 51
++#define ICBID_SLAVE_CRYPTO_0_CFG 52
++#define ICBID_SLAVE_CRYPTO_1_CFG 53
++#define ICBID_SLAVE_IMEM_CFG 54
++#define ICBID_SLAVE_MESSAGE_RAM 55
++#define ICBID_SLAVE_BIMC_CFG 56
++#define ICBID_SLAVE_BOOT_ROM 57
++#define ICBID_SLAVE_CNOC_MNOC_MMSS_CFG 58
++#define ICBID_SLAVE_PMIC_ARB 59
++#define ICBID_SLAVE_SPDM_WRAPPER 60
++#define ICBID_SLAVE_DEHR_CFG 61
++#define ICBID_SLAVE_MPM 62
++#define ICBID_SLAVE_QDSS_CFG 63
++#define ICBID_SLAVE_RBCPR_CFG 64
++#define ICBID_SLAVE_RBCPR_CX_CFG ICBID_SLAVE_RBCPR_CFG
++#define ICBID_SLAVE_RBCPR_QDSS_APU_CFG 65
++#define ICBID_SLAVE_CNOC_MNOC_CFG 66
++#define ICBID_SLAVE_SNOC_MPU_CFG 67
++#define ICBID_SLAVE_CNOC_ONOC_CFG 68
++#define ICBID_SLAVE_PNOC_CFG 69
++#define ICBID_SLAVE_SNOC_CFG 70
++#define ICBID_SLAVE_EBI1_DLL_CFG 71
++#define ICBID_SLAVE_PHY_APU_CFG 72
++#define ICBID_SLAVE_EBI1_PHY_CFG 73
++#define ICBID_SLAVE_RPM 74
++#define ICBID_SLAVE_CNOC_SNOC 75
++#define ICBID_SLAVE_SERVICE_CNOC 76
++#define ICBID_SLAVE_OVIRT_SNOC 77
++#define ICBID_SLAVE_OVIRT_OCMEM 78
++#define ICBID_SLAVE_USB_HS2 79
++#define ICBID_SLAVE_QPIC 80
++#define ICBID_SLAVE_IPS_CFG 81
++#define ICBID_SLAVE_DSI_CFG 82
++#define ICBID_SLAVE_USB3_1 83
++#define ICBID_SLAVE_PCIE_0 84
++#define ICBID_SLAVE_PCIE_1 85
++#define ICBID_SLAVE_PSS_SMMU_CFG 86
++#define ICBID_SLAVE_CRYPTO_2_CFG 87
++#define ICBID_SLAVE_PCIE_0_CFG 88
++#define ICBID_SLAVE_PCIE_1_CFG 89
++#define ICBID_SLAVE_SATA_CFG 90
++#define ICBID_SLAVE_SPSS_GENI_IR 91
++#define ICBID_SLAVE_UFS_CFG 92
++#define ICBID_SLAVE_AVSYNC_CFG 93
++#define ICBID_SLAVE_VPU_CFG 94
++#define ICBID_SLAVE_USB_PHY_CFG 95
++#define ICBID_SLAVE_RBCPR_MX_CFG 96
++#define ICBID_SLAVE_PCIE_PARF 97
++#define ICBID_SLAVE_VCAP_CFG 98
++#define ICBID_SLAVE_EMAC_CFG 99
++#define ICBID_SLAVE_BCAST_CFG 100
++#define ICBID_SLAVE_KLM_CFG 101
++#define ICBID_SLAVE_DISPLAY_PWM 102
++#define ICBID_SLAVE_GENI 103
++#define ICBID_SLAVE_SNOC_BIMC_1 104
++#define ICBID_SLAVE_AUDIO 105
++#define ICBID_SLAVE_CATS_0 106
++#define ICBID_SLAVE_CATS_1 107
++#define ICBID_SLAVE_MM_INT_0 108
++#define ICBID_SLAVE_MM_INT_1 109
++#define ICBID_SLAVE_MM_INT_2 110
++#define ICBID_SLAVE_MM_INT_BIMC 111
++#define ICBID_SLAVE_MMU_MODEM_XPU_CFG 112
++#define ICBID_SLAVE_MSS_INT 113
++#define ICBID_SLAVE_PCNOC_INT_0 114
++#define ICBID_SLAVE_PCNOC_INT_1 115
++#define ICBID_SLAVE_PCNOC_M_0 116
++#define ICBID_SLAVE_PCNOC_M_1 117
++#define ICBID_SLAVE_PCNOC_S_0 118
++#define ICBID_SLAVE_PCNOC_S_1 119
++#define ICBID_SLAVE_PCNOC_S_2 120
++#define ICBID_SLAVE_PCNOC_S_3 121
++#define ICBID_SLAVE_PCNOC_S_4 122
++#define ICBID_SLAVE_PCNOC_S_6 123
++#define ICBID_SLAVE_PCNOC_S_7 124
++#define ICBID_SLAVE_PCNOC_S_8 125
++#define ICBID_SLAVE_PCNOC_S_9 126
++#define ICBID_SLAVE_PRNG_XPU_CFG 127
++#define ICBID_SLAVE_QDSS_INT 128
++#define ICBID_SLAVE_RPM_XPU_CFG 129
++#define ICBID_SLAVE_SNOC_INT_0 130
++#define ICBID_SLAVE_SNOC_INT_1 131
++#define ICBID_SLAVE_SNOC_INT_BIMC 132
++#define ICBID_SLAVE_TCU 133
++#define ICBID_SLAVE_BIMC_INT_0 134
++#define ICBID_SLAVE_BIMC_INT_1 135
++#define ICBID_SLAVE_RICA_CFG 136
++#define ICBID_SLAVE_PCNOC_S_5	189
++#define ICBID_SLAVE_PCNOC_S_7 124
++#define ICBID_SLAVE_PCNOC_INT_2 184
++#define ICBID_SLAVE_PCNOC_INT_3 185
++#define ICBID_SLAVE_PCNOC_INT_4 186
++#define ICBID_SLAVE_PCNOC_INT_5 187
++#define ICBID_SLAVE_PCNOC_INT_6 188
++#define ICBID_SLAVE_USB3_PHY_CFG 182
++#define ICBID_SLAVE_IPA_CFG 183
++
++#define ICBID_SLAVE_A0NOC_SNOC 141
++#define ICBID_SLAVE_A1NOC_SNOC 142
++#define ICBID_SLAVE_A2NOC_SNOC 143
++#define ICBID_SLAVE_BIMC_SNOC_1 138
++#define ICBID_SLAVE_PIMEM 167
++#define ICBID_SLAVE_PIMEM_CFG 168
++#define ICBID_SLAVE_DCC_CFG 155
++#define ICBID_SLAVE_QDSS_RBCPR_APU_CFG 168
++#define ICBID_SLAVE_A0NOC_CFG 144
++#define ICBID_SLAVE_PCIE_2_CFG 165
++#define ICBID_SLAVE_PCIE20_AHB2PHY 163
++#define ICBID_SLAVE_PCIE_2 164
++#define ICBID_SLAVE_A1NOC_CFG 147
++#define ICBID_SLAVE_A1NOC_MPU_CFG 148
++#define ICBID_SLAVE_A1NOC_SMMU_CFG 149
++#define ICBID_SLAVE_A2NOC_CFG 150
++#define ICBID_SLAVE_A2NOC_MPU_CFG 151
++#define ICBID_SLAVE_A2NOC_SMMU_CFG 152
++#define ICBID_SLAVE_AHB2PHY 153
++#define ICBID_SLAVE_HMSS_L3 161
++#define ICBID_SLAVE_LPASS_SMMU_CFG 161
++#define ICBID_SLAVE_MMAGIC_CFG 162
++#define ICBID_SLAVE_SSC_CFG 177
++#define ICBID_SLAVE_VENUS_THROTTLE_CFG 178
++#define ICBID_SLAVE_DISPLAY_THROTTLE_CFG 156
++#define ICBID_SLAVE_CAMERA_THROTTLE_CFG 154
++#define ICBID_SLAVE_DSA_CFG 157
++#define ICBID_SLAVE_DSA_MPU_CFG 158
++#define ICBID_SLAVE_SMMU_CPP_CFG 171
++#define ICBID_SLAVE_SMMU_JPEG_CFG 172
++#define ICBID_SLAVE_SMMU_MDP_CFG 173
++#define ICBID_SLAVE_SMMU_ROTATOR_CFG 174
++#define ICBID_SLAVE_SMMU_VENUS_CFG 175
++#define ICBID_SLAVE_SMMU_VFE_CFG 176
++#define ICBID_SLAVE_A0NOC_MPU_CFG 145
++#define ICBID_SLAVE_A0NOC_SMMU_CFG 146
++#define ICBID_SLAVE_VMEM_CFG 180
++#define ICBID_SLAVE_VMEM 179
++#define ICBID_SLAVE_PNOC_A1NOC 139
++#define ICBID_SLAVE_SNOC_VMEM 140
++#define ICBID_SLAVE_RBCPR_MX 170
++#define ICBID_SLAVE_RBCPR_CX 169
++#define ICBID_SLAVE_PRNG_APU_CFG 190
++#define ICBID_SLAVE_PERIPH_MPU_CFG 191
++#define ICBID_SLAVE_GCNT 192
++#define ICBID_SLAVE_ADSS_CFG 193
++#define ICBID_SLAVE_ADSS_APU 194
++#define ICBID_SLAVE_ADSS_VMIDMT_CFG 195
++#define ICBID_SLAVE_QHSS_APU_CFG 196
++#define ICBID_SLAVE_MDIO 197
++#define ICBID_SLAVE_FEPHY_CFG 198
++#define ICBID_SLAVE_SRIF 199
++#define ICBID_SLAVE_DDRC_CFG 200
++#define ICBID_SLAVE_DDRC_APU_CFG 201
++#define ICBID_SLAVE_DDRC_MPU0_CFG 202
++#define ICBID_SLAVE_DDRC_MPU1_CFG 203
++#define ICBID_SLAVE_DDRC_MPU2_CFG 210
++#define ICBID_SLAVE_ESS_VMIDMT_CFG 211
++#define ICBID_SLAVE_ESS_APU_CFG 212
++#define ICBID_SLAVE_USB2_CFG 213
++#define ICBID_SLAVE_BLSP_CFG 214
++#define ICBID_SLAVE_QPIC_CFG 215
++#define ICBID_SLAVE_SDCC_CFG 216
++#define ICBID_SLAVE_WSS0_VMIDMT_CFG 217
++#define ICBID_SLAVE_WSS0_APU_CFG 218
++#define ICBID_SLAVE_WSS1_VMIDMT_CFG 219
++#define ICBID_SLAVE_WSS1_APU_CFG 220
++#define ICBID_SLAVE_SRVC_PCNOC 221
++#define ICBID_SLAVE_SNOC_DDRC 222
++#define ICBID_SLAVE_A7SS 223
++#define ICBID_SLAVE_WSS0_CFG 224
++#define ICBID_SLAVE_WSS1_CFG 225
++#define ICBID_SLAVE_PCIE 226
++#define ICBID_SLAVE_USB3_CFG 227
++#define ICBID_SLAVE_CRYPTO_CFG 228
++#define ICBID_SLAVE_ESS_CFG 229
++#define ICBID_SLAVE_SRVC_SNOC 230
++#endif
+--- /dev/null
++++ b/include/dt-bindings/msm/msm-bus-rule-ops.h
+@@ -0,0 +1,32 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __MSM_BUS_RULE_OPS_H
++#define __MSM_BUS_RULE_OPS_H
++
++#define FLD_IB	0
++#define FLD_AB	1
++#define FLD_CLK	2
++
++#define OP_LE	0
++#define OP_LT	1
++#define OP_GE	2
++#define OP_GT	3
++#define OP_NOOP	4
++
++#define RULE_STATE_NOT_APPLIED	0
++#define RULE_STATE_APPLIED	1
++
++#define THROTTLE_ON	0
++#define THROTTLE_OFF	1
++
++#endif
+--- /dev/null
++++ b/drivers/bus/msm_bus/Kconfig
+@@ -0,0 +1,19 @@
++config BUS_TOPOLOGY_ADHOC
++	bool "ad-hoc bus scaling topology"
++	depends on ARCH_QCOM
++	default n
++	help
++	  This option enables a driver that can handle adhoc bus topologies.
++	  Adhoc bus topology driver allows one to many connections and maintains
++	  directionality of connections by explicitly listing device connections
++	  thus avoiding illegal routes.
++
++config MSM_BUS_SCALING
++	bool "Bus scaling driver"
++	depends on BUS_TOPOLOGY_ADHOC
++	default n
++	help
++	  This option enables bus scaling on MSM devices.  Bus scaling
++	  allows devices to request the clocks be set to rates sufficient
++	  for the active devices needs without keeping the clocks at max
++	  frequency when a slower speed is sufficient.
+--- /dev/null
++++ b/drivers/bus/msm_bus/Makefile
+@@ -0,0 +1,12 @@
++#
++# Makefile for msm-bus driver specific files
++#
++obj-y += msm_bus_bimc.o msm_bus_noc.o msm_bus_core.o msm_bus_client_api.o \
++	 msm_bus_id.o
++obj-$(CONFIG_OF) += msm_bus_of.o
++
++obj-y += msm_bus_fabric_adhoc.o msm_bus_arb_adhoc.o msm_bus_rules.o
++obj-$(CONFIG_OF) += msm_bus_of_adhoc.o
++obj-$(CONFIG_CORESIGHT) +=  msm_buspm_coresight_adhoc.o
++
++obj-$(CONFIG_DEBUG_FS) += msm_bus_dbg.o
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm-bus-board.h
+@@ -0,0 +1,198 @@
++/* Copyright (c) 2010-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __ASM_ARCH_MSM_BUS_BOARD_H
++#define __ASM_ARCH_MSM_BUS_BOARD_H
++
++#include <linux/types.h>
++#include <linux/input.h>
++
++enum context {
++	DUAL_CTX,
++	ACTIVE_CTX,
++	NUM_CTX
++};
++
++struct msm_bus_fabric_registration {
++	unsigned int id;
++	const char *name;
++	struct msm_bus_node_info *info;
++	unsigned int len;
++	int ahb;
++	const char *fabclk[NUM_CTX];
++	const char *iface_clk;
++	unsigned int offset;
++	unsigned int haltid;
++	unsigned int rpm_enabled;
++	unsigned int nmasters;
++	unsigned int nslaves;
++	unsigned int ntieredslaves;
++	bool il_flag;
++	const struct msm_bus_board_algorithm *board_algo;
++	int hw_sel;
++	void *hw_data;
++	uint32_t qos_freq;
++	uint32_t qos_baseoffset;
++	u64 nr_lim_thresh;
++	uint32_t eff_fact;
++	uint32_t qos_delta;
++	bool virt;
++};
++
++struct msm_bus_device_node_registration {
++	struct msm_bus_node_device_type *info;
++	unsigned int num_devices;
++	bool virt;
++};
++
++enum msm_bus_bw_tier_type {
++	MSM_BUS_BW_TIER1 = 1,
++	MSM_BUS_BW_TIER2,
++	MSM_BUS_BW_COUNT,
++	MSM_BUS_BW_SIZE = 0x7FFFFFFF,
++};
++
++struct msm_bus_halt_vector {
++	uint32_t haltval;
++	uint32_t haltmask;
++};
++
++extern struct msm_bus_fabric_registration msm_bus_apps_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_sys_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_mm_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_sys_fpb_pdata;
++extern struct msm_bus_fabric_registration msm_bus_cpss_fpb_pdata;
++extern struct msm_bus_fabric_registration msm_bus_def_fab_pdata;
++
++extern struct msm_bus_fabric_registration msm_bus_8960_apps_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8960_sys_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8960_mm_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8960_sg_mm_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8960_sys_fpb_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8960_cpss_fpb_pdata;
++
++extern struct msm_bus_fabric_registration msm_bus_8064_apps_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8064_sys_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8064_mm_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8064_sys_fpb_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8064_cpss_fpb_pdata;
++
++extern struct msm_bus_fabric_registration msm_bus_9615_sys_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_9615_def_fab_pdata;
++
++extern struct msm_bus_fabric_registration msm_bus_8930_apps_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8930_sys_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8930_mm_fabric_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8930_sys_fpb_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8930_cpss_fpb_pdata;
++
++extern struct msm_bus_fabric_registration msm_bus_8974_sys_noc_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8974_mmss_noc_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8974_bimc_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8974_ocmem_noc_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8974_periph_noc_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8974_config_noc_pdata;
++extern struct msm_bus_fabric_registration msm_bus_8974_ocmem_vnoc_pdata;
++
++extern struct msm_bus_fabric_registration msm_bus_9625_sys_noc_pdata;
++extern struct msm_bus_fabric_registration msm_bus_9625_bimc_pdata;
++extern struct msm_bus_fabric_registration msm_bus_9625_periph_noc_pdata;
++extern struct msm_bus_fabric_registration msm_bus_9625_config_noc_pdata;
++
++extern int msm_bus_device_match_adhoc(struct device *dev, void *id);
++
++void msm_bus_rpm_set_mt_mask(void);
++int msm_bus_board_rpm_get_il_ids(uint16_t *id);
++int msm_bus_board_get_iid(int id);
++
++#define NFAB_MSM8226 6
++#define NFAB_MSM8610 5
++
++/*
++ * These macros specify the convention followed for allocating
++ * ids to fabrics, masters and slaves for 8x60.
++ *
++ * A node can be identified as a master/slave/fabric by using
++ * these ids.
++ */
++#define FABRIC_ID_KEY 1024
++#define SLAVE_ID_KEY ((FABRIC_ID_KEY) >> 1)
++#define MAX_FAB_KEY 7168  /* OR(All fabric ids) */
++#define INT_NODE_START 10000
++
++#define GET_FABID(id) ((id) & MAX_FAB_KEY)
++
++#define NODE_ID(id) ((id) & (FABRIC_ID_KEY - 1))
++#define IS_SLAVE(id) ((NODE_ID(id)) >= SLAVE_ID_KEY ? 1 : 0)
++#define CHECK_ID(iid, id) (((iid & id) != id) ? -ENXIO : iid)
++
++/*
++ * The following macros are used to format the data for port halt
++ * and unhalt requests.
++ */
++#define MSM_BUS_CLK_HALT 0x1
++#define MSM_BUS_CLK_HALT_MASK 0x1
++#define MSM_BUS_CLK_HALT_FIELDSIZE 0x1
++#define MSM_BUS_CLK_UNHALT 0x0
++
++#define MSM_BUS_MASTER_SHIFT(master, fieldsize) \
++	((master) * (fieldsize))
++
++#define MSM_BUS_SET_BITFIELD(word, fieldmask, fieldvalue) \
++	{	\
++		(word) &= ~(fieldmask);	\
++		(word) |= (fieldvalue);	\
++	}
++
++
++#define MSM_BUS_MASTER_HALT(u32haltmask, u32haltval, master) \
++	MSM_BUS_SET_BITFIELD(u32haltmask, \
++		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
++		MSM_BUS_CLK_HALT_FIELDSIZE), \
++		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
++		MSM_BUS_CLK_HALT_FIELDSIZE))\
++	MSM_BUS_SET_BITFIELD(u32haltval, \
++		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
++		MSM_BUS_CLK_HALT_FIELDSIZE), \
++		MSM_BUS_CLK_HALT<<MSM_BUS_MASTER_SHIFT((master),\
++		MSM_BUS_CLK_HALT_FIELDSIZE))\
++
++#define MSM_BUS_MASTER_UNHALT(u32haltmask, u32haltval, master) \
++	MSM_BUS_SET_BITFIELD(u32haltmask, \
++		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
++		MSM_BUS_CLK_HALT_FIELDSIZE), \
++		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
++		MSM_BUS_CLK_HALT_FIELDSIZE))\
++	MSM_BUS_SET_BITFIELD(u32haltval, \
++		MSM_BUS_CLK_HALT_MASK<<MSM_BUS_MASTER_SHIFT((master),\
++		MSM_BUS_CLK_HALT_FIELDSIZE), \
++		MSM_BUS_CLK_UNHALT<<MSM_BUS_MASTER_SHIFT((master),\
++		MSM_BUS_CLK_HALT_FIELDSIZE))\
++
++#define RPM_BUS_SLAVE_REQ	0x766c7362
++#define RPM_BUS_MASTER_REQ	0x73616d62
++
++enum msm_bus_rpm_slave_field_type {
++	RPM_SLAVE_FIELD_BW = 0x00007762,
++};
++
++enum msm_bus_rpm_mas_field_type {
++	RPM_MASTER_FIELD_BW =		0x00007762,
++	RPM_MASTER_FIELD_BW_T0 =	0x30747762,
++	RPM_MASTER_FIELD_BW_T1 =	0x31747762,
++	RPM_MASTER_FIELD_BW_T2 =	0x32747762,
++};
++
++#include <dt-bindings/msm/msm-bus-ids.h>
++
++
++#endif /*__ASM_ARCH_MSM_BUS_BOARD_H */
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm-bus.h
+@@ -0,0 +1,139 @@
++/* Copyright (c) 2010-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _ARCH_ARM_MACH_MSM_BUS_H
++#define _ARCH_ARM_MACH_MSM_BUS_H
++
++#include <linux/types.h>
++#include <linux/input.h>
++#include <linux/platform_device.h>
++
++/*
++ * Macros for clients to convert their data to ib and ab
++ * Ws : Time window over which to transfer the data in SECONDS
++ * Bs : Size of the data block in bytes
++ * Per : Recurrence period
++ * Tb : Throughput bandwidth to prevent stalling
++ * R  : Ratio of actual bandwidth used to Tb
++ * Ib : Instantaneous bandwidth
++ * Ab : Arbitrated bandwidth
++ *
++ * IB_RECURRBLOCK and AB_RECURRBLOCK:
++ * These are used if the requirement is to transfer a
++ * recurring block of data over a known time window.
++ *
++ * IB_THROUGHPUTBW and AB_THROUGHPUTBW:
++ * These are used for CPU style masters. Here the requirement
++ * is to have minimum throughput bandwidth available to avoid
++ * stalling.
++ */
++#define IB_RECURRBLOCK(Ws, Bs) ((Ws) == 0 ? 0 : ((Bs)/(Ws)))
++#define AB_RECURRBLOCK(Ws, Per) ((Ws) == 0 ? 0 : ((Bs)/(Per)))
++#define IB_THROUGHPUTBW(Tb) (Tb)
++#define AB_THROUGHPUTBW(Tb, R) ((Tb) * (R))
++
++struct msm_bus_vectors {
++	int src; /* Master */
++	int dst; /* Slave */
++	uint64_t ab; /* Arbitrated bandwidth */
++	uint64_t ib; /* Instantaneous bandwidth */
++};
++
++struct msm_bus_paths {
++	int num_paths;
++	struct msm_bus_vectors *vectors;
++};
++
++struct msm_bus_scale_pdata {
++	struct msm_bus_paths *usecase;
++	int num_usecases;
++	const char *name;
++	/*
++	 * If the active_only flag is set to 1, the BW request is applied
++	 * only when at least one CPU is active (powered on). If the flag
++	 * is set to 0, then the BW request is always applied irrespective
++	 * of the CPU state.
++	 */
++	unsigned int active_only;
++};
++
++/* Scaling APIs */
++
++/*
++ * This function returns a handle to the client. This should be used to
++ * call msm_bus_scale_client_update_request.
++ * The function returns 0 if bus driver is unable to register a client
++ */
++
++#if (defined(CONFIG_MSM_BUS_SCALING) || defined(CONFIG_BUS_TOPOLOGY_ADHOC))
++int __init msm_bus_fabric_init_driver(void);
++uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata);
++int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index);
++void msm_bus_scale_unregister_client(uint32_t cl);
++/* AXI Port configuration APIs */
++int msm_bus_axi_porthalt(int master_port);
++int msm_bus_axi_portunhalt(int master_port);
++
++#else
++static inline int __init msm_bus_fabric_init_driver(void) { return 0; }
++
++static inline uint32_t
++msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
++{
++	return 1;
++}
++
++static inline int
++msm_bus_scale_client_update_request(uint32_t cl, unsigned int index)
++{
++	return 0;
++}
++
++static inline void
++msm_bus_scale_unregister_client(uint32_t cl)
++{
++}
++
++static inline int msm_bus_axi_porthalt(int master_port)
++{
++	return 0;
++}
++
++static inline int msm_bus_axi_portunhalt(int master_port)
++{
++	return 0;
++}
++#endif
++
++#if defined(CONFIG_OF) && defined(CONFIG_MSM_BUS_SCALING)
++struct msm_bus_scale_pdata *msm_bus_pdata_from_node(
++		struct platform_device *pdev, struct device_node *of_node);
++struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev);
++void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata);
++#else
++static inline struct msm_bus_scale_pdata
++*msm_bus_cl_get_pdata(struct platform_device *pdev)
++{
++	return NULL;
++}
++
++static inline struct msm_bus_scale_pdata *msm_bus_pdata_from_node(
++		struct platform_device *pdev, struct device_node *of_node)
++{
++	return NULL;
++}
++
++static inline void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata)
++{
++}
++#endif
++#endif /*_ARCH_ARM_MACH_MSM_BUS_H*/
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_adhoc.h
+@@ -0,0 +1,141 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _ARCH_ARM_MACH_MSM_BUS_ADHOC_H
++#define _ARCH_ARM_MACH_MSM_BUS_ADHOC_H
++
++#include <linux/types.h>
++#include <linux/device.h>
++#include "msm-bus-board.h"
++#include "msm-bus.h"
++#include "msm_bus_rules.h"
++#include "msm_bus_core.h"
++
++struct msm_bus_node_device_type;
++struct link_node {
++	uint64_t lnode_ib[NUM_CTX];
++	uint64_t lnode_ab[NUM_CTX];
++	int next;
++	struct device *next_dev;
++	struct list_head link;
++	uint32_t in_use;
++};
++
++/* New types introduced for adhoc topology */
++struct msm_bus_noc_ops {
++	int (*qos_init)(struct msm_bus_node_device_type *dev,
++			void __iomem *qos_base, uint32_t qos_off,
++			uint32_t qos_delta, uint32_t qos_freq);
++	int (*set_bw)(struct msm_bus_node_device_type *dev,
++			void __iomem *qos_base, uint32_t qos_off,
++			uint32_t qos_delta, uint32_t qos_freq);
++	int (*limit_mport)(struct msm_bus_node_device_type *dev,
++			void __iomem *qos_base, uint32_t qos_off,
++			uint32_t qos_delta, uint32_t qos_freq, bool enable_lim,
++			uint64_t lim_bw);
++	bool (*update_bw_reg)(int mode);
++};
++
++struct nodebw {
++	uint64_t ab[NUM_CTX];
++	bool dirty;
++};
++
++struct msm_bus_fab_device_type {
++	void __iomem *qos_base;
++	phys_addr_t pqos_base;
++	size_t qos_range;
++	uint32_t base_offset;
++	uint32_t qos_freq;
++	uint32_t qos_off;
++	uint32_t util_fact;
++	uint32_t vrail_comp;
++	struct msm_bus_noc_ops noc_ops;
++	enum msm_bus_hw_sel bus_type;
++	bool bypass_qos_prg;
++};
++
++struct qos_params_type {
++	int mode;
++	unsigned int prio_lvl;
++	unsigned int prio_rd;
++	unsigned int prio_wr;
++	unsigned int prio1;
++	unsigned int prio0;
++	unsigned int gp;
++	unsigned int thmp;
++	unsigned int ws;
++	int cur_mode;
++	u64 bw_buffer;
++};
++
++struct msm_bus_node_info_type {
++	const char *name;
++	unsigned int id;
++	int mas_rpm_id;
++	int slv_rpm_id;
++	int num_ports;
++	int num_qports;
++	int *qport;
++	struct qos_params_type qos_params;
++	unsigned int num_connections;
++	unsigned int num_blist;
++	bool is_fab_dev;
++	bool virt_dev;
++	bool is_traversed;
++	unsigned int *connections;
++	unsigned int *black_listed_connections;
++	struct device **dev_connections;
++	struct device **black_connections;
++	unsigned int bus_device_id;
++	struct device *bus_device;
++	unsigned int buswidth;
++	struct rule_update_path_info rule;
++	uint64_t lim_bw;
++	uint32_t util_fact;
++	uint32_t vrail_comp;
++};
++
++struct msm_bus_node_device_type {
++	struct msm_bus_node_info_type *node_info;
++	struct msm_bus_fab_device_type *fabdev;
++	int num_lnodes;
++	struct link_node *lnode_list;
++	uint64_t cur_clk_hz[NUM_CTX];
++	struct nodebw node_ab;
++	struct list_head link;
++	unsigned int ap_owned;
++	struct nodeclk clk[NUM_CTX];
++	struct nodeclk qos_clk;
++};
++
++int msm_bus_enable_limiter(struct msm_bus_node_device_type *nodedev,
++				bool throttle_en, uint64_t lim_bw);
++int msm_bus_update_clks(struct msm_bus_node_device_type *nodedev,
++	int ctx, int **dirty_nodes, int *num_dirty);
++int msm_bus_commit_data(int *dirty_nodes, int ctx, int num_dirty);
++int msm_bus_update_bw(struct msm_bus_node_device_type *nodedev, int ctx,
++	int64_t add_bw, int **dirty_nodes, int *num_dirty);
++void *msm_bus_realloc_devmem(struct device *dev, void *p, size_t old_size,
++					size_t new_size, gfp_t flags);
++
++extern struct msm_bus_device_node_registration
++	*msm_bus_of_to_pdata(struct platform_device *pdev);
++extern void msm_bus_arb_setops_adhoc(struct msm_bus_arb_ops *arb_ops);
++extern int msm_bus_bimc_set_ops(struct msm_bus_node_device_type *bus_dev);
++extern int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev);
++extern int msm_bus_of_get_static_rules(struct platform_device *pdev,
++					struct bus_rule_type **static_rule);
++extern int msm_rules_update_path(struct list_head *input_list,
++				struct list_head *output_list);
++extern void print_all_rules(void);
++#endif /* _ARCH_ARM_MACH_MSM_BUS_ADHOC_H */
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_arb_adhoc.c
+@@ -0,0 +1,998 @@
++/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
++ *
++ * This program is Mree software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/mutex.h>
++#include <linux/clk.h>
++#include "msm-bus.h"
++#include "msm_bus_core.h"
++#include "msm_bus_adhoc.h"
++
++#define NUM_CL_HANDLES	50
++#define NUM_LNODES	3
++
++struct bus_search_type {
++	struct list_head link;
++	struct list_head node_list;
++};
++
++struct handle_type {
++	int num_entries;
++	struct msm_bus_client **cl_list;
++};
++
++static struct handle_type handle_list;
++struct list_head input_list;
++struct list_head apply_list;
++
++DEFINE_MUTEX(msm_bus_adhoc_lock);
++
++static bool chk_bl_list(struct list_head *black_list, unsigned int id)
++{
++	struct msm_bus_node_device_type *bus_node = NULL;
++
++	list_for_each_entry(bus_node, black_list, link) {
++		if (bus_node->node_info->id == id)
++			return true;
++	}
++	return false;
++}
++
++static void copy_remaining_nodes(struct list_head *edge_list, struct list_head
++	*traverse_list, struct list_head *route_list)
++{
++	struct bus_search_type *search_node;
++
++	if (list_empty(edge_list) && list_empty(traverse_list))
++		return;
++
++	search_node = kzalloc(sizeof(struct bus_search_type), GFP_KERNEL);
++	INIT_LIST_HEAD(&search_node->node_list);
++	list_splice_init(edge_list, traverse_list);
++	list_splice_init(traverse_list, &search_node->node_list);
++	list_add_tail(&search_node->link, route_list);
++}
++
++/*
++ * Duplicate instantiaion from msm_bus_arb.c. Todo there needs to be a
++ * "util" file for these common func/macros.
++ *
++ * */
++uint64_t msm_bus_div64(unsigned int w, uint64_t bw)
++{
++	uint64_t *b = &bw;
++
++	if ((bw > 0) && (bw < w))
++		return 1;
++
++	switch (w) {
++	case 0:
++		WARN(1, "AXI: Divide by 0 attempted\n");
++	case 1: return bw;
++	case 2: return (bw >> 1);
++	case 4: return (bw >> 2);
++	case 8: return (bw >> 3);
++	case 16: return (bw >> 4);
++	case 32: return (bw >> 5);
++	}
++
++	do_div(*b, w);
++	return *b;
++}
++
++int msm_bus_device_match_adhoc(struct device *dev, void *id)
++{
++	int ret = 0;
++	struct msm_bus_node_device_type *bnode = dev->platform_data;
++
++	if (bnode)
++		ret = (bnode->node_info->id == *(unsigned int *)id);
++	else
++		ret = 0;
++
++	return ret;
++}
++
++static int gen_lnode(struct device *dev,
++			int next_hop, int prev_idx)
++{
++	struct link_node *lnode;
++	struct msm_bus_node_device_type *cur_dev = NULL;
++	int lnode_idx = -1;
++
++	if (!dev)
++		goto exit_gen_lnode;
++
++	cur_dev = dev->platform_data;
++	if (!cur_dev) {
++		MSM_BUS_ERR("%s: Null device ptr", __func__);
++		goto exit_gen_lnode;
++	}
++
++	if (!cur_dev->num_lnodes) {
++		cur_dev->lnode_list = devm_kzalloc(dev,
++				sizeof(struct link_node) * NUM_LNODES,
++								GFP_KERNEL);
++		if (!cur_dev->lnode_list)
++			goto exit_gen_lnode;
++
++		lnode = cur_dev->lnode_list;
++		cur_dev->num_lnodes = NUM_LNODES;
++		lnode_idx = 0;
++	} else {
++		int i;
++		for (i = 0; i < cur_dev->num_lnodes; i++) {
++			if (!cur_dev->lnode_list[i].in_use)
++				break;
++		}
++
++		if (i < cur_dev->num_lnodes) {
++			lnode = &cur_dev->lnode_list[i];
++			lnode_idx = i;
++		} else {
++			struct link_node *realloc_list;
++			size_t cur_size = sizeof(struct link_node) *
++					cur_dev->num_lnodes;
++
++			cur_dev->num_lnodes += NUM_LNODES;
++			realloc_list = msm_bus_realloc_devmem(
++					dev,
++					cur_dev->lnode_list,
++					cur_size,
++					sizeof(struct link_node) *
++					cur_dev->num_lnodes, GFP_KERNEL);
++
++			if (!realloc_list)
++				goto exit_gen_lnode;
++
++			cur_dev->lnode_list = realloc_list;
++			lnode = &cur_dev->lnode_list[i];
++			lnode_idx = i;
++		}
++	}
++
++	lnode->in_use = 1;
++	if (next_hop == cur_dev->node_info->id) {
++		lnode->next = -1;
++		lnode->next_dev = NULL;
++	} else {
++		lnode->next = prev_idx;
++		lnode->next_dev = bus_find_device(&msm_bus_type, NULL,
++					(void *) &next_hop,
++					msm_bus_device_match_adhoc);
++	}
++
++	memset(lnode->lnode_ib, 0, sizeof(uint64_t) * NUM_CTX);
++	memset(lnode->lnode_ab, 0, sizeof(uint64_t) * NUM_CTX);
++
++exit_gen_lnode:
++	return lnode_idx;
++}
++
++static int remove_lnode(struct msm_bus_node_device_type *cur_dev,
++				int lnode_idx)
++{
++	int ret = 0;
++
++	if (!cur_dev) {
++		MSM_BUS_ERR("%s: Null device ptr", __func__);
++		ret = -ENODEV;
++		goto exit_remove_lnode;
++	}
++
++	if (lnode_idx != -1) {
++		if (!cur_dev->num_lnodes ||
++				(lnode_idx > (cur_dev->num_lnodes - 1))) {
++			MSM_BUS_ERR("%s: Invalid Idx %d, num_lnodes %d",
++				__func__, lnode_idx, cur_dev->num_lnodes);
++			ret = -ENODEV;
++			goto exit_remove_lnode;
++		}
++
++		cur_dev->lnode_list[lnode_idx].next = -1;
++		cur_dev->lnode_list[lnode_idx].next_dev = NULL;
++		cur_dev->lnode_list[lnode_idx].in_use = 0;
++	}
++
++exit_remove_lnode:
++	return ret;
++}
++
++static int prune_path(struct list_head *route_list, int dest, int src,
++				struct list_head *black_list, int found)
++{
++	struct bus_search_type *search_node, *temp_search_node;
++	struct msm_bus_node_device_type *bus_node;
++	struct list_head *bl_list;
++	struct list_head *temp_bl_list;
++	int search_dev_id = dest;
++	struct device *dest_dev = bus_find_device(&msm_bus_type, NULL,
++					(void *) &dest,
++					msm_bus_device_match_adhoc);
++	int lnode_hop = -1;
++
++	if (!found)
++		goto reset_links;
++
++	if (!dest_dev) {
++		MSM_BUS_ERR("%s: Can't find dest dev %d", __func__, dest);
++		goto exit_prune_path;
++	}
++
++	lnode_hop = gen_lnode(dest_dev, search_dev_id, lnode_hop);
++
++	list_for_each_entry_reverse(search_node, route_list, link) {
++		list_for_each_entry(bus_node, &search_node->node_list, link) {
++			unsigned int i;
++			for (i = 0; i < bus_node->node_info->num_connections;
++									i++) {
++				if (bus_node->node_info->connections[i] ==
++								search_dev_id) {
++					dest_dev = bus_find_device(
++						&msm_bus_type,
++						NULL,
++						(void *)
++						&bus_node->node_info->
++						id,
++						msm_bus_device_match_adhoc);
++
++					if (!dest_dev) {
++						lnode_hop = -1;
++						goto reset_links;
++					}
++
++					lnode_hop = gen_lnode(dest_dev,
++							search_dev_id,
++							lnode_hop);
++					search_dev_id =
++						bus_node->node_info->id;
++					break;
++				}
++			}
++		}
++	}
++reset_links:
++	list_for_each_entry_safe(search_node, temp_search_node, route_list,
++									link) {
++			list_for_each_entry(bus_node, &search_node->node_list,
++									link)
++				bus_node->node_info->is_traversed = false;
++
++			list_del(&search_node->link);
++			kfree(search_node);
++	}
++
++	list_for_each_safe(bl_list, temp_bl_list, black_list)
++		list_del(bl_list);
++
++exit_prune_path:
++	return lnode_hop;
++}
++
++static void setup_bl_list(struct msm_bus_node_device_type *node,
++				struct list_head *black_list)
++{
++	unsigned int i;
++
++	for (i = 0; i < node->node_info->num_blist; i++) {
++		struct msm_bus_node_device_type *bdev;
++		bdev = node->node_info->black_connections[i]->platform_data;
++		list_add_tail(&bdev->link, black_list);
++	}
++}
++
++static int getpath(int src, int dest)
++{
++	struct list_head traverse_list;
++	struct list_head edge_list;
++	struct list_head route_list;
++	struct list_head black_list;
++	struct device *src_dev = bus_find_device(&msm_bus_type, NULL,
++					(void *) &src,
++					msm_bus_device_match_adhoc);
++	struct msm_bus_node_device_type *src_node;
++	struct bus_search_type *search_node;
++	int found = 0;
++	int depth_index = 0;
++	int first_hop = -1;
++
++	INIT_LIST_HEAD(&traverse_list);
++	INIT_LIST_HEAD(&edge_list);
++	INIT_LIST_HEAD(&route_list);
++	INIT_LIST_HEAD(&black_list);
++
++	if (!src_dev) {
++		MSM_BUS_ERR("%s: Cannot locate src dev %d", __func__, src);
++		goto exit_getpath;
++	}
++
++	src_node = src_dev->platform_data;
++	if (!src_node) {
++		MSM_BUS_ERR("%s:Fatal, Source dev %d not found", __func__, src);
++		goto exit_getpath;
++	}
++	list_add_tail(&src_node->link, &traverse_list);
++
++	while ((!found && !list_empty(&traverse_list))) {
++		struct msm_bus_node_device_type *bus_node = NULL;
++		/* Locate dest_id in the traverse list */
++		list_for_each_entry(bus_node, &traverse_list, link) {
++			if (bus_node->node_info->id == dest) {
++				found = 1;
++				break;
++			}
++		}
++
++		if (!found) {
++			unsigned int i;
++			/* Setup the new edge list */
++			list_for_each_entry(bus_node, &traverse_list, link) {
++				/* Setup list of black-listed nodes */
++				setup_bl_list(bus_node, &black_list);
++
++				for (i = 0; i < bus_node->node_info->
++						num_connections; i++) {
++					bool skip;
++					struct msm_bus_node_device_type
++							*node_conn;
++					node_conn = bus_node->node_info->
++						dev_connections[i]->
++						platform_data;
++					if (node_conn->node_info->
++							is_traversed) {
++						MSM_BUS_ERR("Circ Path %d\n",
++						node_conn->node_info->id);
++						goto reset_traversed;
++					}
++					skip = chk_bl_list(&black_list,
++							bus_node->node_info->
++							connections[i]);
++					if (!skip) {
++						list_add_tail(&node_conn->link,
++							&edge_list);
++						node_conn->node_info->
++							is_traversed = true;
++					}
++				}
++			}
++
++			/* Keep tabs of the previous search list */
++			search_node = kzalloc(sizeof(struct bus_search_type),
++					 GFP_KERNEL);
++			INIT_LIST_HEAD(&search_node->node_list);
++			list_splice_init(&traverse_list,
++					 &search_node->node_list);
++			/* Add the previous search list to a route list */
++			list_add_tail(&search_node->link, &route_list);
++			/* Advancing the list depth */
++			depth_index++;
++			list_splice_init(&edge_list, &traverse_list);
++		}
++	}
++reset_traversed:
++	copy_remaining_nodes(&edge_list, &traverse_list, &route_list);
++	first_hop = prune_path(&route_list, dest, src, &black_list, found);
++
++exit_getpath:
++	return first_hop;
++}
++
++static uint64_t arbitrate_bus_req(struct msm_bus_node_device_type *bus_dev,
++								int ctx)
++{
++	int i;
++	uint64_t max_ib = 0;
++	uint64_t sum_ab = 0;
++	uint64_t bw_max_hz;
++	struct msm_bus_node_device_type *fab_dev = NULL;
++	uint32_t util_fact = 0;
++	uint32_t vrail_comp = 0;
++
++	/* Find max ib */
++	for (i = 0; i < bus_dev->num_lnodes; i++) {
++		max_ib = max(max_ib, bus_dev->lnode_list[i].lnode_ib[ctx]);
++		sum_ab += bus_dev->lnode_list[i].lnode_ab[ctx];
++	}
++	/*
++	 *  Account for Util factor and vrail comp. The new aggregation
++	 *  formula is:
++	 *  Freq_hz = max((sum(ab) * util_fact)/num_chan, max(ib)/vrail_comp)
++	 *				/ bus-width
++	 *  util_fact and vrail comp are obtained from fabric/Node's dts
++	 *  properties.
++	 *  They default to 100 if absent.
++	 */
++	fab_dev = bus_dev->node_info->bus_device->platform_data;
++	/* Don't do this for virtual fabrics */
++	if (fab_dev && fab_dev->fabdev) {
++		util_fact = bus_dev->node_info->util_fact ?
++			bus_dev->node_info->util_fact :
++			fab_dev->fabdev->util_fact;
++		vrail_comp = bus_dev->node_info->vrail_comp ?
++			bus_dev->node_info->vrail_comp :
++			fab_dev->fabdev->vrail_comp;
++		sum_ab *= util_fact;
++		sum_ab = msm_bus_div64(100, sum_ab);
++		max_ib *= 100;
++		max_ib = msm_bus_div64(vrail_comp, max_ib);
++	}
++
++	/* Account for multiple channels if any */
++	if (bus_dev->node_info->num_qports > 1)
++		sum_ab = msm_bus_div64(bus_dev->node_info->num_qports,
++					sum_ab);
++
++	if (!bus_dev->node_info->buswidth) {
++		MSM_BUS_WARN("No bus width found for %d. Using default\n",
++					bus_dev->node_info->id);
++		bus_dev->node_info->buswidth = 8;
++	}
++
++	bw_max_hz = max(max_ib, sum_ab);
++	bw_max_hz = msm_bus_div64(bus_dev->node_info->buswidth,
++					bw_max_hz);
++
++	return bw_max_hz;
++}
++
++static void del_inp_list(struct list_head *list)
++{
++	struct rule_update_path_info *rule_node;
++	struct rule_update_path_info *rule_node_tmp;
++
++	list_for_each_entry_safe(rule_node, rule_node_tmp, list, link)
++		list_del(&rule_node->link);
++}
++
++static void del_op_list(struct list_head *list)
++{
++	struct rule_apply_rcm_info *rule;
++	struct rule_apply_rcm_info *rule_tmp;
++
++	list_for_each_entry_safe(rule, rule_tmp, list, link)
++		list_del(&rule->link);
++}
++
++static int msm_bus_apply_rules(struct list_head *list, bool after_clk_commit)
++{
++	struct rule_apply_rcm_info *rule;
++	struct device *dev = NULL;
++	struct msm_bus_node_device_type *dev_info = NULL;
++	int ret = 0;
++	bool throttle_en = false;
++
++	list_for_each_entry(rule, list, link) {
++		if (!rule)
++			break;
++
++		if (rule && (rule->after_clk_commit != after_clk_commit))
++			continue;
++
++		dev = bus_find_device(&msm_bus_type, NULL,
++				(void *) &rule->id,
++				msm_bus_device_match_adhoc);
++
++		if (!dev) {
++			MSM_BUS_ERR("Can't find dev node for %d", rule->id);
++			continue;
++		}
++		dev_info = dev->platform_data;
++
++		throttle_en = ((rule->throttle == THROTTLE_ON) ? true : false);
++		ret = msm_bus_enable_limiter(dev_info, throttle_en,
++							rule->lim_bw);
++		if (ret)
++			MSM_BUS_ERR("Failed to set limiter for %d", rule->id);
++	}
++
++	return ret;
++}
++
++static uint64_t get_node_aggab(struct msm_bus_node_device_type *bus_dev)
++{
++	int i;
++	int ctx;
++	uint64_t max_agg_ab = 0;
++	uint64_t agg_ab = 0;
++
++	for (ctx = 0; ctx < NUM_CTX; ctx++) {
++		for (i = 0; i < bus_dev->num_lnodes; i++)
++			agg_ab += bus_dev->lnode_list[i].lnode_ab[ctx];
++
++		if (bus_dev->node_info->num_qports > 1)
++			agg_ab = msm_bus_div64(bus_dev->node_info->num_qports,
++							agg_ab);
++
++		max_agg_ab = max(max_agg_ab, agg_ab);
++	}
++
++	return max_agg_ab;
++}
++
++static uint64_t get_node_ib(struct msm_bus_node_device_type *bus_dev)
++{
++	int i;
++	int ctx;
++	uint64_t max_ib = 0;
++
++	for (ctx = 0; ctx < NUM_CTX; ctx++) {
++		for (i = 0; i < bus_dev->num_lnodes; i++)
++			max_ib = max(max_ib,
++				bus_dev->lnode_list[i].lnode_ib[ctx]);
++	}
++	return max_ib;
++}
++
++static int update_path(int src, int dest, uint64_t req_ib, uint64_t req_bw,
++			uint64_t cur_ib, uint64_t cur_bw, int src_idx, int ctx)
++{
++	struct device *src_dev = NULL;
++	struct device *next_dev = NULL;
++	struct link_node *lnode = NULL;
++	struct msm_bus_node_device_type *dev_info = NULL;
++	int curr_idx;
++	int ret = 0;
++	int *dirty_nodes = NULL;
++	int num_dirty = 0;
++	struct rule_update_path_info *rule_node;
++	bool rules_registered = msm_rule_are_rules_registered();
++
++	src_dev = bus_find_device(&msm_bus_type, NULL,
++				(void *) &src,
++				msm_bus_device_match_adhoc);
++
++	if (!src_dev) {
++		MSM_BUS_ERR("%s: Can't find source device %d", __func__, src);
++		ret = -ENODEV;
++		goto exit_update_path;
++	}
++
++	next_dev = src_dev;
++
++	if (src_idx < 0) {
++		MSM_BUS_ERR("%s: Invalid lnode idx %d", __func__, src_idx);
++		ret = -ENXIO;
++		goto exit_update_path;
++	}
++	curr_idx = src_idx;
++
++	INIT_LIST_HEAD(&input_list);
++	INIT_LIST_HEAD(&apply_list);
++
++	while (next_dev) {
++		dev_info = next_dev->platform_data;
++
++		if (curr_idx >= dev_info->num_lnodes) {
++			MSM_BUS_ERR("%s: Invalid lnode Idx %d num lnodes %d",
++			 __func__, curr_idx, dev_info->num_lnodes);
++			ret = -ENXIO;
++			goto exit_update_path;
++		}
++
++		lnode = &dev_info->lnode_list[curr_idx];
++		lnode->lnode_ib[ctx] = req_ib;
++		lnode->lnode_ab[ctx] = req_bw;
++
++		dev_info->cur_clk_hz[ctx] = arbitrate_bus_req(dev_info, ctx);
++
++		/* Start updating the clocks at the first hop.
++		 * Its ok to figure out the aggregated
++		 * request at this node.
++		 */
++		if (src_dev != next_dev) {
++			ret = msm_bus_update_clks(dev_info, ctx, &dirty_nodes,
++								&num_dirty);
++			if (ret) {
++				MSM_BUS_ERR("%s: Failed to update clks dev %d",
++					__func__, dev_info->node_info->id);
++				goto exit_update_path;
++			}
++		}
++
++		ret = msm_bus_update_bw(dev_info, ctx, req_bw, &dirty_nodes,
++								&num_dirty);
++		if (ret) {
++			MSM_BUS_ERR("%s: Failed to update bw dev %d",
++				__func__, dev_info->node_info->id);
++			goto exit_update_path;
++		}
++
++		if (rules_registered) {
++			rule_node = &dev_info->node_info->rule;
++			rule_node->id = dev_info->node_info->id;
++			rule_node->ib = get_node_ib(dev_info);
++			rule_node->ab = get_node_aggab(dev_info);
++			rule_node->clk = max(dev_info->cur_clk_hz[ACTIVE_CTX],
++						dev_info->cur_clk_hz[DUAL_CTX]);
++			list_add_tail(&rule_node->link, &input_list);
++		}
++
++		next_dev = lnode->next_dev;
++		curr_idx = lnode->next;
++	}
++
++	if (rules_registered) {
++		msm_rules_update_path(&input_list, &apply_list);
++		msm_bus_apply_rules(&apply_list, false);
++	}
++
++	msm_bus_commit_data(dirty_nodes, ctx, num_dirty);
++
++	if (rules_registered) {
++		msm_bus_apply_rules(&apply_list, true);
++		del_inp_list(&input_list);
++		del_op_list(&apply_list);
++	}
++exit_update_path:
++	return ret;
++}
++
++static int remove_path(int src, int dst, uint64_t cur_ib, uint64_t cur_ab,
++				int src_idx, int active_only)
++{
++	struct device *src_dev = NULL;
++	struct device *next_dev = NULL;
++	struct link_node *lnode = NULL;
++	struct msm_bus_node_device_type *dev_info = NULL;
++	int ret = 0;
++	int cur_idx = src_idx;
++	int next_idx;
++
++	/* Update the current path to zero out all request from
++	 * this cient on all paths
++	 */
++
++	ret = update_path(src, dst, 0, 0, cur_ib, cur_ab, src_idx,
++							active_only);
++	if (ret) {
++		MSM_BUS_ERR("%s: Error zeroing out path ctx %d",
++					__func__, ACTIVE_CTX);
++		goto exit_remove_path;
++	}
++
++	src_dev = bus_find_device(&msm_bus_type, NULL,
++				(void *) &src,
++				msm_bus_device_match_adhoc);
++	if (!src_dev) {
++		MSM_BUS_ERR("%s: Can't find source device %d", __func__, src);
++		ret = -ENODEV;
++		goto exit_remove_path;
++	}
++
++	next_dev = src_dev;
++
++	while (next_dev) {
++		dev_info = next_dev->platform_data;
++		lnode = &dev_info->lnode_list[cur_idx];
++		next_idx = lnode->next;
++		next_dev = lnode->next_dev;
++		remove_lnode(dev_info, cur_idx);
++		cur_idx = next_idx;
++	}
++
++exit_remove_path:
++	return ret;
++}
++
++static void getpath_debug(int src, int curr, int active_only)
++{
++	struct device *dev_node;
++	struct device *dev_it;
++	unsigned int hop = 1;
++	int idx;
++	struct msm_bus_node_device_type *devinfo;
++	int i;
++
++	dev_node = bus_find_device(&msm_bus_type, NULL,
++				(void *) &src,
++				msm_bus_device_match_adhoc);
++
++	if (!dev_node) {
++		MSM_BUS_ERR("SRC NOT FOUND %d", src);
++		return;
++	}
++
++	idx = curr;
++	devinfo = dev_node->platform_data;
++	dev_it = dev_node;
++
++	MSM_BUS_ERR("Route list Src %d", src);
++	while (dev_it) {
++		struct msm_bus_node_device_type *busdev =
++			devinfo->node_info->bus_device->platform_data;
++
++		MSM_BUS_ERR("Hop[%d] at Device %d ctx %d", hop,
++					devinfo->node_info->id, active_only);
++
++		for (i = 0; i < NUM_CTX; i++) {
++			MSM_BUS_ERR("dev info sel ib %llu",
++						devinfo->cur_clk_hz[i]);
++			MSM_BUS_ERR("dev info sel ab %llu",
++						devinfo->node_ab.ab[i]);
++		}
++
++		dev_it = devinfo->lnode_list[idx].next_dev;
++		idx = devinfo->lnode_list[idx].next;
++		if (dev_it)
++			devinfo = dev_it->platform_data;
++
++		MSM_BUS_ERR("Bus Device %d", busdev->node_info->id);
++		MSM_BUS_ERR("Bus Clock %llu", busdev->clk[active_only].rate);
++
++		if (idx < 0)
++			break;
++		hop++;
++	}
++}
++
++static void unregister_client_adhoc(uint32_t cl)
++{
++	int i;
++	struct msm_bus_scale_pdata *pdata;
++	int lnode, src, curr, dest;
++	uint64_t  cur_clk, cur_bw;
++	struct msm_bus_client *client;
++
++	mutex_lock(&msm_bus_adhoc_lock);
++	if (!cl) {
++		MSM_BUS_ERR("%s: Null cl handle passed unregister\n",
++				__func__);
++		goto exit_unregister_client;
++	}
++	client = handle_list.cl_list[cl];
++	pdata = client->pdata;
++	if (!pdata) {
++		MSM_BUS_ERR("%s: Null pdata passed to unregister\n",
++				__func__);
++		goto exit_unregister_client;
++	}
++
++	curr = client->curr;
++	if (curr >= pdata->num_usecases) {
++		MSM_BUS_ERR("Invalid index Defaulting curr to 0");
++		curr = 0;
++	}
++
++	MSM_BUS_DBG("%s: Unregistering client %p", __func__, client);
++
++	for (i = 0; i < pdata->usecase->num_paths; i++) {
++		src = client->pdata->usecase[curr].vectors[i].src;
++		dest = client->pdata->usecase[curr].vectors[i].dst;
++
++		lnode = client->src_pnode[i];
++		cur_clk = client->pdata->usecase[curr].vectors[i].ib;
++		cur_bw = client->pdata->usecase[curr].vectors[i].ab;
++		remove_path(src, dest, cur_clk, cur_bw, lnode,
++						pdata->active_only);
++	}
++	msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_UNREGISTER, cl);
++	kfree(client->src_pnode);
++	kfree(client);
++	handle_list.cl_list[cl] = NULL;
++exit_unregister_client:
++	mutex_unlock(&msm_bus_adhoc_lock);
++	return;
++}
++
++static int alloc_handle_lst(int size)
++{
++	int ret = 0;
++	struct msm_bus_client **t_cl_list;
++
++	if (!handle_list.num_entries) {
++		t_cl_list = kzalloc(sizeof(struct msm_bus_client *)
++			* NUM_CL_HANDLES, GFP_KERNEL);
++		if (ZERO_OR_NULL_PTR(t_cl_list)) {
++			ret = -ENOMEM;
++			MSM_BUS_ERR("%s: Failed to allocate handles list",
++								__func__);
++			goto exit_alloc_handle_lst;
++		}
++		handle_list.cl_list = t_cl_list;
++		handle_list.num_entries += NUM_CL_HANDLES;
++	} else {
++		t_cl_list = krealloc(handle_list.cl_list,
++				sizeof(struct msm_bus_client *) *
++				handle_list.num_entries + NUM_CL_HANDLES,
++				GFP_KERNEL);
++		if (ZERO_OR_NULL_PTR(t_cl_list)) {
++			ret = -ENOMEM;
++			MSM_BUS_ERR("%s: Failed to allocate handles list",
++								__func__);
++			goto exit_alloc_handle_lst;
++		}
++
++		memset(&handle_list.cl_list[handle_list.num_entries], 0,
++			NUM_CL_HANDLES * sizeof(struct msm_bus_client *));
++		handle_list.num_entries += NUM_CL_HANDLES;
++		handle_list.cl_list = t_cl_list;
++	}
++exit_alloc_handle_lst:
++	return ret;
++}
++
++static uint32_t gen_handle(struct msm_bus_client *client)
++{
++	uint32_t handle = 0;
++	int i;
++	int ret = 0;
++
++	for (i = 0; i < handle_list.num_entries; i++) {
++		if (i && !handle_list.cl_list[i]) {
++			handle = i;
++			break;
++		}
++	}
++
++	if (!handle) {
++		ret = alloc_handle_lst(NUM_CL_HANDLES);
++
++		if (ret) {
++			MSM_BUS_ERR("%s: Failed to allocate handle list",
++							__func__);
++			goto exit_gen_handle;
++		}
++		handle = i + 1;
++	}
++	handle_list.cl_list[handle] = client;
++exit_gen_handle:
++	return handle;
++}
++
++static uint32_t register_client_adhoc(struct msm_bus_scale_pdata *pdata)
++{
++	int src, dest;
++	int i;
++	struct msm_bus_client *client = NULL;
++	int *lnode;
++	uint32_t handle = 0;
++
++	mutex_lock(&msm_bus_adhoc_lock);
++	client = kzalloc(sizeof(struct msm_bus_client), GFP_KERNEL);
++	if (!client) {
++		MSM_BUS_ERR("%s: Error allocating client data", __func__);
++		goto exit_register_client;
++	}
++	client->pdata = pdata;
++
++	lnode = kzalloc(pdata->usecase->num_paths * sizeof(int), GFP_KERNEL);
++	if (ZERO_OR_NULL_PTR(lnode)) {
++		MSM_BUS_ERR("%s: Error allocating pathnode ptr!", __func__);
++		goto exit_register_client;
++	}
++	client->src_pnode = lnode;
++
++	for (i = 0; i < pdata->usecase->num_paths; i++) {
++		src = pdata->usecase->vectors[i].src;
++		dest = pdata->usecase->vectors[i].dst;
++
++		if ((src < 0) || (dest < 0)) {
++			MSM_BUS_ERR("%s:Invalid src/dst.src %d dest %d",
++				__func__, src, dest);
++			goto exit_register_client;
++		}
++
++		lnode[i] = getpath(src, dest);
++		if (lnode[i] < 0) {
++			MSM_BUS_ERR("%s:Failed to find path.src %d dest %d",
++				__func__, src, dest);
++			goto exit_register_client;
++		}
++	}
++
++	handle = gen_handle(client);
++	msm_bus_dbg_client_data(client->pdata, MSM_BUS_DBG_REGISTER,
++					handle);
++	MSM_BUS_DBG("%s:Client handle %d %s", __func__, handle,
++						client->pdata->name);
++exit_register_client:
++	mutex_unlock(&msm_bus_adhoc_lock);
++	return handle;
++}
++
++static int update_request_adhoc(uint32_t cl, unsigned int index)
++{
++	int i, ret = 0;
++	struct msm_bus_scale_pdata *pdata;
++	int lnode, src, curr, dest;
++	uint64_t req_clk, req_bw, curr_clk, curr_bw;
++	struct msm_bus_client *client;
++	const char *test_cl = "Null";
++	bool log_transaction = false;
++
++	mutex_lock(&msm_bus_adhoc_lock);
++
++	if (!cl) {
++		MSM_BUS_ERR("%s: Invalid client handle %d", __func__, cl);
++		ret = -ENXIO;
++		goto exit_update_request;
++	}
++
++	client = handle_list.cl_list[cl];
++	pdata = client->pdata;
++	if (!pdata) {
++		MSM_BUS_ERR("%s: Client data Null.[client didn't register]",
++				__func__);
++		ret = -ENXIO;
++		goto exit_update_request;
++	}
++
++	if (index >= pdata->num_usecases) {
++		MSM_BUS_ERR("Client %u passed invalid index: %d\n",
++			cl, index);
++		ret = -ENXIO;
++		goto exit_update_request;
++	}
++
++	if (client->curr == index) {
++		MSM_BUS_DBG("%s: Not updating client request idx %d unchanged",
++				__func__, index);
++		goto exit_update_request;
++	}
++
++	curr = client->curr;
++	client->curr = index;
++
++	if (!strcmp(test_cl, pdata->name))
++		log_transaction = true;
++
++	MSM_BUS_DBG("%s: cl: %u index: %d curr: %d num_paths: %d\n", __func__,
++		cl, index, client->curr, client->pdata->usecase->num_paths);
++
++	for (i = 0; i < pdata->usecase->num_paths; i++) {
++		src = client->pdata->usecase[index].vectors[i].src;
++		dest = client->pdata->usecase[index].vectors[i].dst;
++
++		lnode = client->src_pnode[i];
++		req_clk = client->pdata->usecase[index].vectors[i].ib;
++		req_bw = client->pdata->usecase[index].vectors[i].ab;
++		if (curr < 0) {
++			curr_clk = 0;
++			curr_bw = 0;
++		} else {
++			curr_clk = client->pdata->usecase[curr].vectors[i].ib;
++			curr_bw = client->pdata->usecase[curr].vectors[i].ab;
++			MSM_BUS_DBG("%s:ab: %llu ib: %llu\n", __func__,
++					curr_bw, curr_clk);
++		}
++
++		ret = update_path(src, dest, req_clk, req_bw,
++				curr_clk, curr_bw, lnode, pdata->active_only);
++
++		if (ret) {
++			MSM_BUS_ERR("%s: Update path failed! %d ctx %d\n",
++					__func__, ret, ACTIVE_CTX);
++			goto exit_update_request;
++		}
++
++		if (log_transaction)
++			getpath_debug(src, lnode, pdata->active_only);
++	}
++	msm_bus_dbg_client_data(client->pdata, index , cl);
++exit_update_request:
++	mutex_unlock(&msm_bus_adhoc_lock);
++	return ret;
++}
++
++/**
++ *  msm_bus_arb_setops_adhoc() : Setup the bus arbitration ops
++ *  @ arb_ops: pointer to the arb ops.
++ */
++void msm_bus_arb_setops_adhoc(struct msm_bus_arb_ops *arb_ops)
++{
++	arb_ops->register_client = register_client_adhoc;
++	arb_ops->update_request = update_request_adhoc;
++	arb_ops->unregister_client = unregister_client_adhoc;
++}
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_bimc.c
+@@ -0,0 +1,2112 @@
++/* Copyright (c) 2012-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#define pr_fmt(fmt) "AXI: BIMC: %s(): " fmt, __func__
++
++#include <linux/slab.h>
++#include <linux/io.h>
++#include "msm-bus-board.h"
++#include "msm_bus_core.h"
++#include "msm_bus_bimc.h"
++#include "msm_bus_adhoc.h"
++#include <trace/events/trace_msm_bus.h>
++
++enum msm_bus_bimc_slave_block {
++	SLAVE_BLOCK_RESERVED = 0,
++	SLAVE_BLOCK_SLAVE_WAY,
++	SLAVE_BLOCK_XPU,
++	SLAVE_BLOCK_ARBITER,
++	SLAVE_BLOCK_SCMO,
++};
++
++enum bke_sw {
++	BKE_OFF = 0,
++	BKE_ON = 1,
++};
++
++/* M_Generic */
++
++#define M_REG_BASE(b)		((b) + 0x00008000)
++
++#define M_COMPONENT_INFO_ADDR(b, n) \
++		(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000000)
++enum bimc_m_component_info {
++	M_COMPONENT_INFO_RMSK		= 0xffffff,
++	M_COMPONENT_INFO_INSTANCE_BMSK	= 0xff0000,
++	M_COMPONENT_INFO_INSTANCE_SHFT	= 0x10,
++	M_COMPONENT_INFO_SUB_TYPE_BMSK	= 0xff00,
++	M_COMPONENT_INFO_SUB_TYPE_SHFT	= 0x8,
++	M_COMPONENT_INFO_TYPE_BMSK	= 0xff,
++	M_COMPONENT_INFO_TYPE_SHFT	= 0x0,
++};
++
++#define M_CONFIG_INFO_0_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000020)
++enum bimc_m_config_info_0 {
++	M_CONFIG_INFO_0_RMSK			= 0xff00ffff,
++	M_CONFIG_INFO_0_SYNC_MODE_BMSK		= 0xff000000,
++	M_CONFIG_INFO_0_SYNC_MODE_SHFT		= 0x18,
++	M_CONFIG_INFO_0_CONNECTION_TYPE_BMSK	= 0xff00,
++	M_CONFIG_INFO_0_CONNECTION_TYPE_SHFT	= 0x8,
++	M_CONFIG_INFO_0_FUNC_BMSK		= 0xff,
++	M_CONFIG_INFO_0_FUNC_SHFT		= 0x0,
++};
++
++#define M_CONFIG_INFO_1_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000030)
++enum bimc_m_config_info_1 {
++	M_CONFIG_INFO_1_RMSK			= 0xffffffff,
++	M_CONFIG_INFO_1_SWAY_CONNECTIVITY_BMSK	= 0xffffffff,
++	M_CONFIG_INFO_1_SWAY_CONNECTIVITY_SHFT	= 0x0,
++};
++
++#define M_CONFIG_INFO_2_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000040)
++enum bimc_m_config_info_2 {
++	M_CONFIG_INFO_2_RMSK			= 0xffffffff,
++	M_CONFIG_INFO_2_M_DATA_WIDTH_BMSK	= 0xffff0000,
++	M_CONFIG_INFO_2_M_DATA_WIDTH_SHFT	= 0x10,
++	M_CONFIG_INFO_2_M_TID_WIDTH_BMSK	= 0xff00,
++	M_CONFIG_INFO_2_M_TID_WIDTH_SHFT	= 0x8,
++	M_CONFIG_INFO_2_M_MID_WIDTH_BMSK	= 0xff,
++	M_CONFIG_INFO_2_M_MID_WIDTH_SHFT	= 0x0,
++};
++
++#define M_CONFIG_INFO_3_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000050)
++enum bimc_m_config_info_3 {
++	M_CONFIG_INFO_3_RMSK			= 0xffffffff,
++	M_CONFIG_INFO_3_RCH_DEPTH_BMSK		= 0xff000000,
++	M_CONFIG_INFO_3_RCH_DEPTH_SHFT		= 0x18,
++	M_CONFIG_INFO_3_BCH_DEPTH_BMSK		= 0xff0000,
++	M_CONFIG_INFO_3_BCH_DEPTH_SHFT		= 0x10,
++	M_CONFIG_INFO_3_WCH_DEPTH_BMSK		= 0xff00,
++	M_CONFIG_INFO_3_WCH_DEPTH_SHFT		= 0x8,
++	M_CONFIG_INFO_3_ACH_DEPTH_BMSK		= 0xff,
++	M_CONFIG_INFO_3_ACH_DEPTH_SHFT		= 0x0,
++};
++
++#define M_CONFIG_INFO_4_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000060)
++enum bimc_m_config_info_4 {
++	M_CONFIG_INFO_4_RMSK			= 0xffff,
++	M_CONFIG_INFO_4_REORDER_BUF_DEPTH_BMSK	= 0xff00,
++	M_CONFIG_INFO_4_REORDER_BUF_DEPTH_SHFT	= 0x8,
++	M_CONFIG_INFO_4_REORDER_TABLE_DEPTH_BMSK	= 0xff,
++	M_CONFIG_INFO_4_REORDER_TABLE_DEPTH_SHFT	= 0x0,
++};
++
++#define M_CONFIG_INFO_5_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000070)
++enum bimc_m_config_info_5 {
++	M_CONFIG_INFO_5_RMSK			= 0x111,
++	M_CONFIG_INFO_5_MP2ARB_PIPELINE_EN_BMSK	= 0x100,
++	M_CONFIG_INFO_5_MP2ARB_PIPELINE_EN_SHFT	= 0x8,
++	M_CONFIG_INFO_5_MPBUF_PIPELINE_EN_BMSK	= 0x10,
++	M_CONFIG_INFO_5_MPBUF_PIPELINE_EN_SHFT	= 0x4,
++	M_CONFIG_INFO_5_M2MP_PIPELINE_EN_BMSK	= 0x1,
++	M_CONFIG_INFO_5_M2MP_PIPELINE_EN_SHFT	= 0x0,
++};
++
++#define M_INT_STATUS_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000100)
++enum bimc_m_int_status {
++	M_INT_STATUS_RMSK			= 0x3,
++};
++
++#define M_INT_CLR_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000108)
++enum bimc_m_int_clr {
++	M_INT_CLR_RMSK			= 0x3,
++};
++
++#define M_INT_EN_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x0000010c)
++enum bimc_m_int_en {
++	M_INT_EN_RMSK			= 0x3,
++};
++
++#define M_CLK_CTRL_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000200)
++enum bimc_m_clk_ctrl {
++	M_CLK_CTRL_RMSK				= 0x3,
++	M_CLK_CTRL_MAS_CLK_GATING_EN_BMSK	= 0x2,
++	M_CLK_CTRL_MAS_CLK_GATING_EN_SHFT	= 0x1,
++	M_CLK_CTRL_CORE_CLK_GATING_EN_BMSK	= 0x1,
++	M_CLK_CTRL_CORE_CLK_GATING_EN_SHFT	= 0x0,
++};
++
++#define M_MODE_ADDR(b, n) \
++		(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000210)
++enum bimc_m_mode {
++	M_MODE_RMSK				= 0xf0000011,
++	M_MODE_WR_GATHER_BEATS_BMSK		= 0xf0000000,
++	M_MODE_WR_GATHER_BEATS_SHFT		= 0x1c,
++	M_MODE_NARROW_WR_BMSK			= 0x10,
++	M_MODE_NARROW_WR_SHFT			= 0x4,
++	M_MODE_ORDERING_MODEL_BMSK		= 0x1,
++	M_MODE_ORDERING_MODEL_SHFT		= 0x0,
++};
++
++#define M_PRIOLVL_OVERRIDE_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000230)
++enum bimc_m_priolvl_override {
++	M_PRIOLVL_OVERRIDE_RMSK			= 0x301,
++	M_PRIOLVL_OVERRIDE_BMSK			= 0x300,
++	M_PRIOLVL_OVERRIDE_SHFT			= 0x8,
++	M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK	= 0x1,
++	M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT	= 0x0,
++};
++
++#define M_RD_CMD_OVERRIDE_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000240)
++enum bimc_m_read_command_override {
++	M_RD_CMD_OVERRIDE_RMSK			= 0x3071f7f,
++	M_RD_CMD_OVERRIDE_AREQPRIO_BMSK		= 0x3000000,
++	M_RD_CMD_OVERRIDE_AREQPRIO_SHFT		= 0x18,
++	M_RD_CMD_OVERRIDE_AMEMTYPE_BMSK		= 0x70000,
++	M_RD_CMD_OVERRIDE_AMEMTYPE_SHFT		= 0x10,
++	M_RD_CMD_OVERRIDE_ATRANSIENT_BMSK		= 0x1000,
++	M_RD_CMD_OVERRIDE_ATRANSIENT_SHFT		= 0xc,
++	M_RD_CMD_OVERRIDE_ASHARED_BMSK		= 0x800,
++	M_RD_CMD_OVERRIDE_ASHARED_SHFT		= 0xb,
++	M_RD_CMD_OVERRIDE_AREDIRECT_BMSK		= 0x400,
++	M_RD_CMD_OVERRIDE_AREDIRECT_SHFT		= 0xa,
++	M_RD_CMD_OVERRIDE_AOOO_BMSK			= 0x200,
++	M_RD_CMD_OVERRIDE_AOOO_SHFT			= 0x9,
++	M_RD_CMD_OVERRIDE_AINNERSHARED_BMSK		= 0x100,
++	M_RD_CMD_OVERRIDE_AINNERSHARED_SHFT		= 0x8,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK	= 0x40,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT	= 0x6,
++	M_RD_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_BMSK	= 0x20,
++	M_RD_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_SHFT	= 0x5,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK	= 0x10,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT	= 0x4,
++	M_RD_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK	= 0x8,
++	M_RD_CMD_OVERRIDE_OVERRIDE_ASHARED_SHFT	= 0x3,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AREDIRECT_BMSK	= 0x4,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AREDIRECT_SHFT	= 0x2,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AOOO_BMSK		= 0x2,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AOOO_SHFT		= 0x1,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_BMSK	= 0x1,
++	M_RD_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_SHFT	= 0x0,
++};
++
++#define M_WR_CMD_OVERRIDE_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000250)
++enum bimc_m_write_command_override {
++	M_WR_CMD_OVERRIDE_RMSK			= 0x3071f7f,
++	M_WR_CMD_OVERRIDE_AREQPRIO_BMSK		= 0x3000000,
++	M_WR_CMD_OVERRIDE_AREQPRIO_SHFT		= 0x18,
++	M_WR_CMD_OVERRIDE_AMEMTYPE_BMSK		= 0x70000,
++	M_WR_CMD_OVERRIDE_AMEMTYPE_SHFT		= 0x10,
++	M_WR_CMD_OVERRIDE_ATRANSIENT_BMSK	= 0x1000,
++	M_WR_CMD_OVERRIDE_ATRANSIENT_SHFT	= 0xc,
++	M_WR_CMD_OVERRIDE_ASHARED_BMSK		= 0x800,
++	M_WR_CMD_OVERRIDE_ASHARED_SHFT		= 0xb,
++	M_WR_CMD_OVERRIDE_AREDIRECT_BMSK		= 0x400,
++	M_WR_CMD_OVERRIDE_AREDIRECT_SHFT		= 0xa,
++	M_WR_CMD_OVERRIDE_AOOO_BMSK			= 0x200,
++	M_WR_CMD_OVERRIDE_AOOO_SHFT			= 0x9,
++	M_WR_CMD_OVERRIDE_AINNERSHARED_BMSK		= 0x100,
++	M_WR_CMD_OVERRIDE_AINNERSHARED_SHFT		= 0x8,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK	= 0x40,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT	= 0x6,
++	M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_BMSK	= 0x20,
++	M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_SHFT	= 0x5,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK	= 0x10,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT	= 0x4,
++	M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK	= 0x8,
++	M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_SHFT	= 0x3,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AREDIRECT_BMSK	= 0x4,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AREDIRECT_SHFT	= 0x2,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AOOO_BMSK	= 0x2,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AOOO_SHFT	= 0x1,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_BMSK	= 0x1,
++	M_WR_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_SHFT	= 0x0,
++};
++
++#define M_BKE_EN_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000300)
++enum bimc_m_bke_en {
++	M_BKE_EN_RMSK			= 0x1,
++	M_BKE_EN_EN_BMSK		= 0x1,
++	M_BKE_EN_EN_SHFT		= 0x0,
++};
++
++/* Grant Period registers */
++#define M_BKE_GP_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000304)
++enum bimc_m_bke_grant_period {
++	M_BKE_GP_RMSK		= 0x3ff,
++	M_BKE_GP_GP_BMSK	= 0x3ff,
++	M_BKE_GP_GP_SHFT	= 0x0,
++};
++
++/* Grant count register.
++ * The Grant count register represents a signed 16 bit
++ * value, range 0-0x7fff
++ */
++#define M_BKE_GC_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000308)
++enum bimc_m_bke_grant_count {
++	M_BKE_GC_RMSK			= 0xffff,
++	M_BKE_GC_GC_BMSK		= 0xffff,
++	M_BKE_GC_GC_SHFT		= 0x0,
++};
++
++/* Threshold High Registers */
++#define M_BKE_THH_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000320)
++enum bimc_m_bke_thresh_high {
++	M_BKE_THH_RMSK		= 0xffff,
++	M_BKE_THH_THRESH_BMSK	= 0xffff,
++	M_BKE_THH_THRESH_SHFT	= 0x0,
++};
++
++/* Threshold Medium Registers */
++#define M_BKE_THM_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000324)
++enum bimc_m_bke_thresh_medium {
++	M_BKE_THM_RMSK		= 0xffff,
++	M_BKE_THM_THRESH_BMSK	= 0xffff,
++	M_BKE_THM_THRESH_SHFT	= 0x0,
++};
++
++/* Threshold Low Registers */
++#define M_BKE_THL_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000328)
++enum bimc_m_bke_thresh_low {
++	M_BKE_THL_RMSK			= 0xffff,
++	M_BKE_THL_THRESH_BMSK		= 0xffff,
++	M_BKE_THL_THRESH_SHFT		= 0x0,
++};
++
++#define M_BKE_HEALTH_0_CONFIG_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000340)
++enum bimc_m_bke_health_0 {
++	M_BKE_HEALTH_0_CONFIG_RMSK			= 0x80000303,
++	M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK		= 0x80000000,
++	M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_SHFT		= 0x1f,
++	M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK		= 0x300,
++	M_BKE_HEALTH_0_CONFIG_AREQPRIO_SHFT		= 0x8,
++	M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK		= 0x3,
++	M_BKE_HEALTH_0_CONFIG_PRIOLVL_SHFT		= 0x0,
++};
++
++#define M_BKE_HEALTH_1_CONFIG_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000344)
++enum bimc_m_bke_health_1 {
++	M_BKE_HEALTH_1_CONFIG_RMSK			= 0x80000303,
++	M_BKE_HEALTH_1_CONFIG_LIMIT_CMDS_BMSK		= 0x80000000,
++	M_BKE_HEALTH_1_CONFIG_LIMIT_CMDS_SHFT		= 0x1f,
++	M_BKE_HEALTH_1_CONFIG_AREQPRIO_BMSK		= 0x300,
++	M_BKE_HEALTH_1_CONFIG_AREQPRIO_SHFT		= 0x8,
++	M_BKE_HEALTH_1_CONFIG_PRIOLVL_BMSK		= 0x3,
++	M_BKE_HEALTH_1_CONFIG_PRIOLVL_SHFT		= 0x0,
++};
++
++#define M_BKE_HEALTH_2_CONFIG_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000348)
++enum bimc_m_bke_health_2 {
++	M_BKE_HEALTH_2_CONFIG_RMSK			= 0x80000303,
++	M_BKE_HEALTH_2_CONFIG_LIMIT_CMDS_BMSK		= 0x80000000,
++	M_BKE_HEALTH_2_CONFIG_LIMIT_CMDS_SHFT		= 0x1f,
++	M_BKE_HEALTH_2_CONFIG_AREQPRIO_BMSK		= 0x300,
++	M_BKE_HEALTH_2_CONFIG_AREQPRIO_SHFT		= 0x8,
++	M_BKE_HEALTH_2_CONFIG_PRIOLVL_BMSK		= 0x3,
++	M_BKE_HEALTH_2_CONFIG_PRIOLVL_SHFT		= 0x0,
++};
++
++#define M_BKE_HEALTH_3_CONFIG_ADDR(b, n) \
++	(M_REG_BASE(b) + (0x4000 * (n)) + 0x0000034c)
++enum bimc_m_bke_health_3 {
++	M_BKE_HEALTH_3_CONFIG_RMSK			= 0x303,
++	M_BKE_HEALTH_3_CONFIG_AREQPRIO_BMSK	= 0x300,
++	M_BKE_HEALTH_3_CONFIG_AREQPRIO_SHFT	= 0x8,
++	M_BKE_HEALTH_3_CONFIG_PRIOLVL_BMSK		= 0x3,
++	M_BKE_HEALTH_3_CONFIG_PRIOLVL_SHFT		= 0x0,
++};
++
++#define M_BUF_STATUS_ADDR(b, n) \
++		(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000400)
++enum bimc_m_buf_status {
++	M_BUF_STATUS_RMSK			= 0xf03f030,
++	M_BUF_STATUS_RCH_DATA_WR_FULL_BMSK	= 0x8000000,
++	M_BUF_STATUS_RCH_DATA_WR_FULL_SHFT	= 0x1b,
++	M_BUF_STATUS_RCH_DATA_WR_EMPTY_BMSK	= 0x4000000,
++	M_BUF_STATUS_RCH_DATA_WR_EMPTY_SHFT	= 0x1a,
++	M_BUF_STATUS_RCH_CTRL_WR_FULL_BMSK	= 0x2000000,
++	M_BUF_STATUS_RCH_CTRL_WR_FULL_SHFT	= 0x19,
++	M_BUF_STATUS_RCH_CTRL_WR_EMPTY_BMSK	= 0x1000000,
++	M_BUF_STATUS_RCH_CTRL_WR_EMPTY_SHFT	= 0x18,
++	M_BUF_STATUS_BCH_WR_FULL_BMSK		= 0x20000,
++	M_BUF_STATUS_BCH_WR_FULL_SHFT		= 0x11,
++	M_BUF_STATUS_BCH_WR_EMPTY_BMSK		= 0x10000,
++	M_BUF_STATUS_BCH_WR_EMPTY_SHFT		= 0x10,
++	M_BUF_STATUS_WCH_DATA_RD_FULL_BMSK	= 0x8000,
++	M_BUF_STATUS_WCH_DATA_RD_FULL_SHFT	= 0xf,
++	M_BUF_STATUS_WCH_DATA_RD_EMPTY_BMSK	= 0x4000,
++	M_BUF_STATUS_WCH_DATA_RD_EMPTY_SHFT	= 0xe,
++	M_BUF_STATUS_WCH_CTRL_RD_FULL_BMSK	= 0x2000,
++	M_BUF_STATUS_WCH_CTRL_RD_FULL_SHFT	= 0xd,
++	M_BUF_STATUS_WCH_CTRL_RD_EMPTY_BMSK	= 0x1000,
++	M_BUF_STATUS_WCH_CTRL_RD_EMPTY_SHFT	= 0xc,
++	M_BUF_STATUS_ACH_RD_FULL_BMSK		= 0x20,
++	M_BUF_STATUS_ACH_RD_FULL_SHFT		= 0x5,
++	M_BUF_STATUS_ACH_RD_EMPTY_BMSK		= 0x10,
++	M_BUF_STATUS_ACH_RD_EMPTY_SHFT		= 0x4,
++};
++/*BIMC Generic */
++
++#define S_REG_BASE(b)	((b) + 0x00048000)
++
++#define S_COMPONENT_INFO_ADDR(b, n) \
++	(S_REG_BASE(b) + (0x8000 * (n)) + 0x00000000)
++enum bimc_s_component_info {
++	S_COMPONENT_INFO_RMSK			= 0xffffff,
++	S_COMPONENT_INFO_INSTANCE_BMSK		= 0xff0000,
++	S_COMPONENT_INFO_INSTANCE_SHFT		= 0x10,
++	S_COMPONENT_INFO_SUB_TYPE_BMSK		= 0xff00,
++	S_COMPONENT_INFO_SUB_TYPE_SHFT		= 0x8,
++	S_COMPONENT_INFO_TYPE_BMSK		= 0xff,
++	S_COMPONENT_INFO_TYPE_SHFT		= 0x0,
++};
++
++#define S_HW_INFO_ADDR(b, n) \
++	(S_REG_BASE(b) + (0x80000 * (n)) + 0x00000010)
++enum bimc_s_hw_info {
++	S_HW_INFO_RMSK				= 0xffffffff,
++	S_HW_INFO_MAJOR_BMSK			= 0xff000000,
++	S_HW_INFO_MAJOR_SHFT			= 0x18,
++	S_HW_INFO_BRANCH_BMSK			= 0xff0000,
++	S_HW_INFO_BRANCH_SHFT			= 0x10,
++	S_HW_INFO_MINOR_BMSK			= 0xff00,
++	S_HW_INFO_MINOR_SHFT			= 0x8,
++	S_HW_INFO_ECO_BMSK			= 0xff,
++	S_HW_INFO_ECO_SHFT			= 0x0,
++};
++
++
++/* S_SCMO_GENERIC */
++
++#define S_SCMO_REG_BASE(b)	((b) + 0x00048000)
++
++#define S_SCMO_CONFIG_INFO_0_ADDR(b, n) \
++		(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000020)
++enum bimc_s_scmo_config_info_0 {
++	S_SCMO_CONFIG_INFO_0_RMSK		= 0xffffffff,
++	S_SCMO_CONFIG_INFO_0_DATA_WIDTH_BMSK	= 0xffff0000,
++	S_SCMO_CONFIG_INFO_0_DATA_WIDTH_SHFT	= 0x10,
++	S_SCMO_CONFIG_INFO_0_TID_WIDTH_BMSK	= 0xff00,
++	S_SCMO_CONFIG_INFO_0_TID_WIDTH_SHFT	= 0x8,
++	S_SCMO_CONFIG_INFO_0_MID_WIDTH_BMSK	= 0xff,
++	S_SCMO_CONFIG_INFO_0_MID_WIDTH_SHFT	= 0x0,
++};
++
++#define S_SCMO_CONFIG_INFO_1_ADDR(b, n) \
++		(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000030)
++enum bimc_s_scmo_config_info_1 {
++	S_SCMO_CONFIG_INFO_1_RMSK			= 0xffffffff,
++	S_SCMO_CONFIG_INFO_1_MPORT_CONNECTIVITY_BMSK	= 0xffffffff,
++	S_SCMO_CONFIG_INFO_1_MPORT_CONNECTIVITY_SHFT	= 0x0,
++};
++
++#define S_SCMO_CONFIG_INFO_2_ADDR(b, n) \
++		(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000040)
++enum bimc_s_scmo_config_info_2 {
++	S_SCMO_CONFIG_INFO_2_RMSK			= 0xff00ff,
++	S_SCMO_CONFIG_INFO_2_NUM_GLOBAL_MONS_BMSK	= 0xff0000,
++	S_SCMO_CONFIG_INFO_2_NUM_GLOBAL_MONS_SHFT	= 0x10,
++	S_SCMO_CONFIG_INFO_2_VMID_WIDTH_BMSK	= 0xff,
++	S_SCMO_CONFIG_INFO_2_VMID_WIDTH_SHFT	= 0x0,
++};
++
++#define S_SCMO_CONFIG_INFO_3_ADDR(b, n) \
++		(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000050)
++enum bimc_s_scmo_config_info_3 {
++	S_SCMO_CONFIG_INFO_3_RMSK			= 0xffffffff,
++	S_SCMO_CONFIG_INFO_3_RCH0_CTRL_DEPTH_BMSK	= 0xff000000,
++	S_SCMO_CONFIG_INFO_3_RCH0_CTRL_DEPTH_SHFT	= 0x18,
++	S_SCMO_CONFIG_INFO_3_RCH0_DEPTH_BMSK		= 0xff0000,
++	S_SCMO_CONFIG_INFO_3_RCH0_DEPTH_SHFT		= 0x10,
++	S_SCMO_CONFIG_INFO_3_BCH_DEPTH_BMSK		= 0xff00,
++	S_SCMO_CONFIG_INFO_3_BCH_DEPTH_SHFT		= 0x8,
++	S_SCMO_CONFIG_INFO_3_WCH_DEPTH_BMSK		= 0xff,
++	S_SCMO_CONFIG_INFO_3_WCH_DEPTH_SHFT		= 0x0,
++};
++
++#define S_SCMO_CONFIG_INFO_4_ADDR(b, n) \
++		(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000060)
++enum bimc_s_scmo_config_info_4 {
++	S_SCMO_CONFIG_INFO_4_RMSK			= 0xffff,
++	S_SCMO_CONFIG_INFO_4_RCH1_CTRL_DEPTH_BMSK	= 0xff00,
++	S_SCMO_CONFIG_INFO_4_RCH1_CTRL_DEPTH_SHFT	= 0x8,
++	S_SCMO_CONFIG_INFO_4_RCH1_DEPTH_BMSK		= 0xff,
++	S_SCMO_CONFIG_INFO_4_RCH1_DEPTH_SHFT		= 0x0,
++};
++
++#define S_SCMO_CONFIG_INFO_5_ADDR(b, n) \
++		(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000070)
++enum bimc_s_scmo_config_info_5 {
++	S_SCMO_CONFIG_INFO_5_RMSK			= 0xffff,
++	S_SCMO_CONFIG_INFO_5_DPE_CQ_DEPTH_BMSK		= 0xff00,
++	S_SCMO_CONFIG_INFO_5_DPE_CQ_DEPTH_SHFT		= 0x8,
++	S_SCMO_CONFIG_INFO_5_DDR_BUS_WIDTH_BMSK		= 0xff,
++	S_SCMO_CONFIG_INFO_5_DDR_BUS_WIDTH_SHFT		= 0x0,
++};
++
++#define S_SCMO_CONFIG_INFO_6_ADDR(b, n) \
++		(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000080)
++enum bimc_s_scmo_config_info_6 {
++	S_SCMO_CONFIG_INFO_6_RMSK			= 0x1111,
++	S_SCMO_CONFIG_INFO_6_WBUFC_PIPE_BMSK		= 0x1000,
++	S_SCMO_CONFIG_INFO_6_WBUFC_PIPE_SHFT		= 0xc,
++	S_SCMO_CONFIG_INFO_6_RDOPT_PIPE_BMSK		= 0x100,
++	S_SCMO_CONFIG_INFO_6_RDOPT_PIPE_SHFT		= 0x8,
++	S_SCMO_CONFIG_INFO_6_ACHAN_INTF_PIPE_BMSK	= 0x10,
++	S_SCMO_CONFIG_INFO_6_ACHAN_INTF_PIPE_SHFT	= 0x4,
++	S_SCMO_CONFIG_INFO_6_ADDR_DECODE_HT_BMSK	= 0x1,
++	S_SCMO_CONFIG_INFO_6_ADDR_DECODE_HT_SHFT	= 0x0,
++};
++
++#define S_SCMO_INT_STATUS_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000100)
++enum bimc_s_scmo_int_status {
++	S_SCMO_INT_STATUS_RMSK			= 0x1,
++	S_SCMO_INT_STATUS_ERR_OCCURED_BMSK	= 0x1,
++	S_SCMO_INT_STATUS_ERR_OCCURED_SHFT	= 0x0,
++};
++
++#define S_SCMO_INT_CLR_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000108)
++enum bimc_s_scmo_int_clr {
++	S_SCMO_INT_CLR_RMSK		= 0x1,
++	S_SCMO_INT_CLR_IRQ_CLR_BMSK	= 0x1,
++	S_SCMO_INT_CLR_IRQ_CLR_SHFT	= 0x0,
++};
++
++#define S_SCMO_INT_EN_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x0000010c)
++enum bimc_s_scmo_int_en {
++	S_SCMO_INT_EN_RMSK		= 0x1,
++	S_SCMO_INT_EN_IRQ_EN_BMSK	= 0x1,
++	S_SCMO_INT_EN_IRQ_EN_SHFT	= 0x0,
++};
++
++#define S_SCMO_ESYN_ADDR_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000120)
++enum bimc_s_scmo_esyn_addr {
++	S_SCMO_ESYN_ADDR_RMSK				= 0xffffffff,
++	S_SCMO_ESYN_ADDR_ESYN_ADDR_ERR_ADDR_BMSK	= 0xffffffff,
++	S_SCMO_ESYN_ADDR_ESYN_ADDR_ERR_ADDR_SHFT	= 0x0,
++};
++
++#define S_SCMO_ESYN_APACKET_0_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000128)
++enum bimc_s_scmo_esyn_apacket_0 {
++	S_SCMO_ESYN_APACKET_0_RMSK			= 0xff1fffff,
++	S_SCMO_ESYN_APACKET_0_ERR_ATID_BMSK		= 0xff000000,
++	S_SCMO_ESYN_APACKET_0_ERR_ATID_SHFT		= 0x18,
++	S_SCMO_ESYN_APACKET_0_ERR_AVMID_BMSK		= 0x1f0000,
++	S_SCMO_ESYN_APACKET_0_ERR_AVMID_SHFT		= 0x10,
++	S_SCMO_ESYN_APACKET_0_ERR_AMID_BMSK		= 0xffff,
++	S_SCMO_ESYN_APACKET_0_ERR_AMID_SHFT		= 0x0,
++};
++
++#define S_SCMO_ESYN_APACKET_1_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x0000012c)
++enum bimc_s_scmo_esyn_apacket_1 {
++	S_SCMO_ESYN_APACKET_1_RMSK			= 0x10ff117,
++	S_SCMO_ESYN_APACKET_1_ERR_CODE_BMSK		= 0x1000000,
++	S_SCMO_ESYN_APACKET_1_ERR_CODE_SHFT		= 0x18,
++	S_SCMO_ESYN_APACKET_1_ERR_ALEN_BMSK		= 0xf0000,
++	S_SCMO_ESYN_APACKET_1_ERR_ALEN_SHFT		= 0x10,
++	S_SCMO_ESYN_APACKET_1_ERR_ASIZE_BMSK		= 0xe000,
++	S_SCMO_ESYN_APACKET_1_ERR_ASIZE_SHFT		= 0xd,
++	S_SCMO_ESYN_APACKET_1_ERR_ABURST_BMSK		= 0x1000,
++	S_SCMO_ESYN_APACKET_1_ERR_ABURST_SHFT		= 0xc,
++	S_SCMO_ESYN_APACKET_1_ERR_AEXCLUSIVE_BMSK	= 0x100,
++	S_SCMO_ESYN_APACKET_1_ERR_AEXCLUSIVE_SHFT	= 0x8,
++	S_SCMO_ESYN_APACKET_1_ERR_APRONTS_BMSK		= 0x10,
++	S_SCMO_ESYN_APACKET_1_ERR_APRONTS_SHFT		= 0x4,
++	S_SCMO_ESYN_APACKET_1_ERR_AOOORD_BMSK		= 0x4,
++	S_SCMO_ESYN_APACKET_1_ERR_AOOORD_SHFT		= 0x2,
++	S_SCMO_ESYN_APACKET_1_ERR_AOOOWR_BMSK		= 0x2,
++	S_SCMO_ESYN_APACKET_1_ERR_AOOOWR_SHFT		= 0x1,
++	S_SCMO_ESYN_APACKET_1_ERR_AWRITE_BMSK		= 0x1,
++	S_SCMO_ESYN_APACKET_1_ERR_AWRITE_SHFT		= 0x0,
++};
++
++#define S_SCMO_CLK_CTRL_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000200)
++enum bimc_s_scmo_clk_ctrl {
++	S_SCMO_CLK_CTRL_RMSK				= 0xffff1111,
++	S_SCMO_CLK_CTRL_PEN_CMD_CG_EN_BMSK		= 0x10000,
++	S_SCMO_CLK_CTRL_PEN_CMD_CG_EN_SHFT		= 0x10,
++	S_SCMO_CLK_CTRL_RCH_CG_EN_BMSK			= 0x1000,
++	S_SCMO_CLK_CTRL_RCH_CG_EN_SHFT			= 0xc,
++	S_SCMO_CLK_CTRL_FLUSH_CG_EN_BMSK		= 0x100,
++	S_SCMO_CLK_CTRL_FLUSH_CG_EN_SHFT		= 0x8,
++	S_SCMO_CLK_CTRL_WCH_CG_EN_BMSK			= 0x10,
++	S_SCMO_CLK_CTRL_WCH_CG_EN_SHFT			= 0x4,
++	S_SCMO_CLK_CTRL_ACH_CG_EN_BMSK			= 0x1,
++	S_SCMO_CLK_CTRL_ACH_CG_EN_SHFT			= 0x0,
++};
++
++#define S_SCMO_SLV_INTERLEAVE_CFG_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000400)
++enum bimc_s_scmo_slv_interleave_cfg {
++	S_SCMO_SLV_INTERLEAVE_CFG_RMSK			= 0xff,
++	S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS1_BMSK	= 0x10,
++	S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS1_SHFT	= 0x4,
++	S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS0_BMSK	= 0x1,
++	S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS0_SHFT	= 0x0,
++};
++
++#define S_SCMO_ADDR_BASE_CSn_ADDR(b, n, o)	\
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000410 + 0x4 * (o))
++enum bimc_s_scmo_addr_base_csn {
++	S_SCMO_ADDR_BASE_CSn_RMSK			= 0xffff,
++	S_SCMO_ADDR_BASE_CSn_MAXn			= 1,
++	S_SCMO_ADDR_BASE_CSn_ADDR_BASE_BMSK		= 0xfc,
++	S_SCMO_ADDR_BASE_CSn_ADDR_BASE_SHFT		= 0x2,
++};
++
++#define S_SCMO_ADDR_MAP_CSn_ADDR(b, n, o) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000420 + 0x4 * (o))
++enum bimc_s_scmo_addr_map_csn {
++	S_SCMO_ADDR_MAP_CSn_RMSK		= 0xffff,
++	S_SCMO_ADDR_MAP_CSn_MAXn		= 1,
++	S_SCMO_ADDR_MAP_CSn_RANK_EN_BMSK	= 0x8000,
++	S_SCMO_ADDR_MAP_CSn_RANK_EN_SHFT	= 0xf,
++	S_SCMO_ADDR_MAP_CSn_ADDR_MODE_BMSK	= 0x1000,
++	S_SCMO_ADDR_MAP_CSn_ADDR_MODE_SHFT	= 0xc,
++	S_SCMO_ADDR_MAP_CSn_BANK_SIZE_BMSK	= 0x100,
++	S_SCMO_ADDR_MAP_CSn_BANK_SIZE_SHFT	= 0x8,
++	S_SCMO_ADDR_MAP_CSn_ROW_SIZE_BMSK	= 0x30,
++	S_SCMO_ADDR_MAP_CSn_ROW_SIZE_SHFT	= 0x4,
++	S_SCMO_ADDR_MAP_CSn_COL_SIZE_BMSK	= 0x3,
++	S_SCMO_ADDR_MAP_CSn_COL_SIZE_SHFT	= 0x0,
++};
++
++#define S_SCMO_ADDR_MASK_CSn_ADDR(b, n, o) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000430 + 0x4 * (0))
++enum bimc_s_scmo_addr_mask_csn {
++	S_SCMO_ADDR_MASK_CSn_RMSK		= 0xffff,
++	S_SCMO_ADDR_MASK_CSn_MAXn		= 1,
++	S_SCMO_ADDR_MASK_CSn_ADDR_MASK_BMSK	= 0xfc,
++	S_SCMO_ADDR_MASK_CSn_ADDR_MASK_SHFT	= 0x2,
++};
++
++#define S_SCMO_SLV_STATUS_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000450)
++enum bimc_s_scmo_slv_status {
++	S_SCMO_SLV_STATUS_RMSK				= 0xff3,
++	S_SCMO_SLV_STATUS_GLOBAL_MONS_IN_USE_BMSK	= 0xff0,
++	S_SCMO_SLV_STATUS_GLOBAL_MONS_IN_USE_SHFT	= 0x4,
++	S_SCMO_SLV_STATUS_SLAVE_IDLE_BMSK		= 0x3,
++	S_SCMO_SLV_STATUS_SLAVE_IDLE_SHFT		= 0x0,
++};
++
++#define S_SCMO_CMD_BUF_CFG_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000500)
++enum bimc_s_scmo_cmd_buf_cfg {
++	S_SCMO_CMD_BUF_CFG_RMSK				= 0xf1f,
++	S_SCMO_CMD_BUF_CFG_CMD_ORDERING_BMSK		= 0x300,
++	S_SCMO_CMD_BUF_CFG_CMD_ORDERING_SHFT		= 0x8,
++	S_SCMO_CMD_BUF_CFG_HP_CMD_AREQPRIO_MAP_BMSK	= 0x10,
++	S_SCMO_CMD_BUF_CFG_HP_CMD_AREQPRIO_MAP_SHFT	= 0x4,
++	S_SCMO_CMD_BUF_CFG_HP_CMD_Q_DEPTH_BMSK		= 0x7,
++	S_SCMO_CMD_BUF_CFG_HP_CMD_Q_DEPTH_SHFT		= 0x0,
++};
++
++#define S_SCM_CMD_BUF_STATUS_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000520)
++enum bimc_s_scm_cmd_buf_status {
++	S_SCMO_CMD_BUF_STATUS_RMSK				= 0x77,
++	S_SCMO_CMD_BUF_STATUS_HP_CMD_BUF_ENTRIES_IN_USE_BMSK	= 0x70,
++	S_SCMO_CMD_BUF_STATUS_HP_CMD_BUF_ENTRIES_IN_USE_SHFT	= 0x4,
++	S_SCMO_CMD_BUF_STATUS_LP_CMD_BUF_ENTRIES_IN_USE_BMSK	= 0x7,
++	S_SCMO_CMD_BUF_STATUS_LP_CMD_BUF_ENTRIES_IN_USE_SHFT	= 0x0,
++};
++
++#define S_SCMO_RCH_SEL_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000540)
++enum bimc_s_scmo_rch_sel {
++	S_SCMO_RCH_SEL_RMSK			= 0xffffffff,
++	S_SCMO_CMD_BUF_STATUS_RCH_PORTS_BMSK	= 0xffffffff,
++	S_SCMO_CMD_BUF_STATUS_RCH_PORTS_SHFT	= 0x0,
++};
++
++#define S_SCMO_RCH_BKPR_CFG_ADDR(b, n) \
++		(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000544)
++enum bimc_s_scmo_rch_bkpr_cfg {
++	S_SCMO_RCH_BKPR_CFG_RMSK			= 0xffffffff,
++	S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_HI_TH_BMSK	= 0x3f000000,
++	S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_HI_TH_SHFT	= 0x18,
++	S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_LO_TH_BMSK	= 0x3f0000,
++	S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_LO_TH_SHFT	= 0x10,
++	S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_HI_TH_BMSK	= 0x3f00,
++	S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_HI_TH_SHFT	= 0x8,
++	S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_LO_TH_BMSK	= 0x3f,
++	S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_LO_TH_SHFT	= 0x0,
++};
++
++#define S_SCMO_RCH_STATUS_ADDR(b, n) \
++		(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000560)
++enum bimc_s_scmo_rch_status {
++	S_SCMO_RCH_STATUS_RMSK				= 0x33333,
++	S_SCMO_RCH_STATUS_PRQ_FIFO_FULL_BMSK		= 0x20000,
++	S_SCMO_RCH_STATUS_PRQ_FIFO_FULL_SHFT		= 0x11,
++	S_SCMO_RCH_STATUS_PRQ_FIFO_EMPTY_BMSK		= 0x10000,
++	S_SCMO_RCH_STATUS_PRQ_FIFO_EMPTY_SHFT		= 0x10,
++	S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_FULL_BMSK	= 0x2000,
++	S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_FULL_SHFT	= 0xd,
++	S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_EMPTY_BMSK	= 0x1000,
++	S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_EMPTY_SHFT	= 0xc,
++	S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_FULL_BMSK	= 0x200,
++	S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_FULL_SHFT	= 0x9,
++	S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_EMPTY_BMSK	= 0x100,
++	S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_EMPTY_SHFT	= 0x8,
++	S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_FULL_BMSK	= 0x20,
++	S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_FULL_SHFT	= 0x5,
++	S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_EMPTY_BMSK	= 0x10,
++	S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_EMPTY_SHFT	= 0x4,
++	S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_FULL_BMSK	= 0x2,
++	S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_FULL_SHFT	= 0x1,
++	S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_EMPTY_BMSK	= 0x1,
++	S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_EMPTY_SHFT	= 0x0,
++};
++
++#define S_SCMO_WCH_BUF_CFG_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000580)
++enum bimc_s_scmo_wch_buf_cfg {
++	S_SCMO_WCH_BUF_CFG_RMSK				= 0xff,
++	S_SCMO_WCH_BUF_CFG_WRITE_BLOCK_READ_BMSK	= 0x10,
++	S_SCMO_WCH_BUF_CFG_WRITE_BLOCK_READ_SHFT	= 0x4,
++	S_SCMO_WCH_BUF_CFG_COALESCE_EN_BMSK		= 0x1,
++	S_SCMO_WCH_BUF_CFG_COALESCE_EN_SHFT		= 0x0,
++};
++
++#define S_SCMO_WCH_STATUS_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x000005a0)
++enum bimc_s_scmo_wch_status {
++	S_SCMO_WCH_STATUS_RMSK				= 0x333,
++	S_SCMO_WCH_STATUS_BRESP_FIFO_FULL_BMSK		= 0x200,
++	S_SCMO_WCH_STATUS_BRESP_FIFO_FULL_SHFT		= 0x9,
++	S_SCMO_WCH_STATUS_BRESP_FIFO_EMPTY_BMSK		= 0x100,
++	S_SCMO_WCH_STATUS_BRESP_FIFO_EMPTY_SHFT		= 0x8,
++	S_SCMO_WCH_STATUS_WDATA_FIFO_FULL_BMSK		= 0x20,
++	S_SCMO_WCH_STATUS_WDATA_FIFO_FULL_SHFT		= 0x5,
++	S_SCMO_WCH_STATUS_WDATA_FIFO_EMPTY_BMSK		= 0x10,
++	S_SCMO_WCH_STATUS_WDATA_FIFO_EMPTY_SHFT		= 0x4,
++	S_SCMO_WCH_STATUS_WBUF_FULL_BMSK		= 0x2,
++	S_SCMO_WCH_STATUS_WBUF_FULL_SHFT		= 0x1,
++	S_SCMO_WCH_STATUS_WBUF_EMPTY_BMSK		= 0x1,
++	S_SCMO_WCH_STATUS_WBUF_EMPTY_SHFT		= 0x0,
++};
++
++#define S_SCMO_FLUSH_CFG_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x000005c0)
++enum bimc_s_scmo_flush_cfg {
++	S_SCMO_FLUSH_CFG_RMSK				= 0xffffffff,
++	S_SCMO_FLUSH_CFG_FLUSH_IN_ORDER_BMSK		= 0x10000000,
++	S_SCMO_FLUSH_CFG_FLUSH_IN_ORDER_SHFT		= 0x1c,
++	S_SCMO_FLUSH_CFG_FLUSH_IDLE_DELAY_BMSK		= 0x3ff0000,
++	S_SCMO_FLUSH_CFG_FLUSH_IDLE_DELAY_SHFT		= 0x10,
++	S_SCMO_FLUSH_CFG_FLUSH_UPPER_LIMIT_BMSK		= 0xf00,
++	S_SCMO_FLUSH_CFG_FLUSH_UPPER_LIMIT_SHFT		= 0x8,
++	S_SCMO_FLUSH_CFG_FLUSH_LOWER_LIMIT_BMSK		= 0xf,
++	S_SCMO_FLUSH_CFG_FLUSH_LOWER_LIMIT_SHFT		= 0x0,
++};
++
++#define S_SCMO_FLUSH_CMD_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x000005c4)
++enum bimc_s_scmo_flush_cmd {
++	S_SCMO_FLUSH_CMD_RMSK				= 0xf,
++	S_SCMO_FLUSH_CMD_FLUSH_ALL_BUF_BMSK		= 0x3,
++	S_SCMO_FLUSH_CMD_FLUSH_ALL_BUF_SHFT		= 0x0,
++};
++
++#define S_SCMO_CMD_OPT_CFG0_ADDR(b, n) \
++	(S_SCM0_REG_BASE(b) + (0x8000 * (n)) + 0x00000700)
++enum bimc_s_scmo_cmd_opt_cfg0 {
++	S_SCMO_CMD_OPT_CFG0_RMSK		= 0xffffff,
++	S_SCMO_CMD_OPT_CFG0_IGNORE_BANK_UNAVL_BMSK	= 0x100000,
++	S_SCMO_CMD_OPT_CFG0_IGNORE_BANK_UNAVL_SHFT	= 0x14,
++	S_SCMO_CMD_OPT_CFG0_MASK_CMDOUT_PRI_BMSK	= 0x10000,
++	S_SCMO_CMD_OPT_CFG0_MASK_CMDOUT_PRI_SHFT	= 0x10,
++	S_SCMO_CMD_OPT_CFG0_DPE_CMD_REORDERING_BMSK	= 0x1000,
++	S_SCMO_CMD_OPT_CFG0_DPE_CMD_REORDERING_SHFT	= 0xc,
++	S_SCMO_CMD_OPT_CFG0_WR_OPT_EN_BMSK		= 0x100,
++	S_SCMO_CMD_OPT_CFG0_WR_OPT_EN_SHFT		= 0x8,
++	S_SCMO_CMD_OPT_CFG0_RD_OPT_EN_BMSK		= 0x10,
++	S_SCMO_CMD_OPT_CFG0_RD_OPT_EN_SHFT		= 0x4,
++	S_SCMO_CMD_OPT_CFG0_PAGE_MGMT_POLICY_BMSK	= 0x1,
++	S_SCMO_CMD_OPT_CFG0_PAGE_MGMT_POLICY_SHFT	= 0x0,
++};
++
++#define S_SCMO_CMD_OPT_CFG1_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000704)
++enum bimc_s_scmo_cmd_opt_cfg1 {
++	S_SCMO_CMD_OPT_CFG1_RMSK			= 0xffffffff,
++	S_SCMO_CMD_OPT_CFG1_HSTP_CMD_TIMEOUT_BMSK	= 0x1f000000,
++	S_SCMO_CMD_OPT_CFG1_HSTP_CMD_TIMEOUT_SHFT	= 0x18,
++	S_SCMO_CMD_OPT_CFG1_HP_CMD_TIMEOUT_BMSK		= 0x1f0000,
++	S_SCMO_CMD_OPT_CFG1_HP_CMD_TIMEOUT_SHFT		= 0x10,
++	S_SCMO_CMD_OPT_CFG1_MP_CMD_TIMEOUT_BMSK		= 0x1f00,
++	S_SCMO_CMD_OPT_CFG1_MP_CMD_TIMEOUT_SHFT		= 0x8,
++	S_SCMO_CMD_OPT_CFG1_LP_CMD_TIMEOUT_BMSK		= 0x1f,
++	S_SCMO_CMD_OPT_CFG1_LP_CMD_TIMEOUT_SHFT		= 0x0,
++};
++
++#define S_SCMO_CMD_OPT_CFG2_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000708)
++enum bimc_s_scmo_cmd_opt_cfg2 {
++	S_SCMO_CMD_OPT_CFG2_RMSK			= 0xff,
++	S_SCMO_CMD_OPT_CFG2_RWOPT_CMD_TIMEOUT_BMSK	= 0xf,
++	S_SCMO_CMD_OPT_CFG2_RWOPT_CMD_TIMEOUT_SHFT	= 0x0,
++};
++
++#define S_SCMO_CMD_OPT_CFG3_ADDR(b, n) \
++	(S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x0000070c)
++enum bimc_s_scmo_cmd_opt_cfg3 {
++	S_SCMO_CMD_OPT_CFG3_RMSK			= 0xff,
++	S_SCMO_CMD_OPT_CFG3_FLUSH_CMD_TIMEOUT_BMSK	= 0xf,
++	S_SCMO_CMD_OPT_CFG3_FLUSH_CMD_TIMEOUT_SHFT	= 0x0,
++};
++
++/* S_SWAY_GENERIC */
++#define S_SWAY_REG_BASE(b)	((b) + 0x00048000)
++
++#define S_SWAY_CONFIG_INFO_0_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000020)
++enum bimc_s_sway_config_info_0 {
++	S_SWAY_CONFIG_INFO_0_RMSK		= 0xff0000ff,
++	S_SWAY_CONFIG_INFO_0_SYNC_MODE_BMSK	= 0xff000000,
++	S_SWAY_CONFIG_INFO_0_SYNC_MODE_SHFT	= 0x18,
++	S_SWAY_CONFIG_INFO_0_FUNC_BMSK		= 0xff,
++	S_SWAY_CONFIG_INFO_0_FUNC_SHFT		= 0x0,
++};
++
++#define S_SWAY_CONFIG_INFO_1_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000030)
++enum bimc_s_sway_config_info_1 {
++	S_SWAY_CONFIG_INFO_1_RMSK			= 0xffffffff,
++	S_SWAY_CONFIG_INFO_1_MPORT_CONNECTIVITY_BMSK	= 0xffffffff,
++	S_SWAY_CONFIG_INFO_1_MPORT_CONNECTIVITY_SHFT	= 0x0,
++};
++
++#define S_SWAY_CONFIG_INFO_2_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000040)
++enum bimc_s_sway_config_info_2 {
++	S_SWAY_CONFIG_INFO_2_RMSK			= 0xffff0000,
++	S_SWAY_CONFIG_INFO_2_MPORT_CONNECTIVITY_BMSK	= 0xffff0000,
++	S_SWAY_CONFIG_INFO_2_MPORT_CONNECTIVITY_SHFT	= 0x10,
++};
++
++#define S_SWAY_CONFIG_INFO_3_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000050)
++enum bimc_s_sway_config_info_3 {
++	S_SWAY_CONFIG_INFO_3_RMSK			= 0xffffffff,
++	S_SWAY_CONFIG_INFO_3_RCH0_DEPTH_BMSK		= 0xff000000,
++	S_SWAY_CONFIG_INFO_3_RCH0_DEPTH_SHFT		= 0x18,
++	S_SWAY_CONFIG_INFO_3_BCH_DEPTH_BMSK		= 0xff0000,
++	S_SWAY_CONFIG_INFO_3_BCH_DEPTH_SHFT		= 0x10,
++	S_SWAY_CONFIG_INFO_3_WCH_DEPTH_BMSK		= 0xff,
++	S_SWAY_CONFIG_INFO_3_WCH_DEPTH_SHFT		= 0x0,
++};
++
++#define S_SWAY_CONFIG_INFO_4_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000060)
++enum bimc_s_sway_config_info_4 {
++	S_SWAY_CONFIG_INFO_4_RMSK			= 0x800000ff,
++	S_SWAY_CONFIG_INFO_4_DUAL_RCH_EN_BMSK		= 0x80000000,
++	S_SWAY_CONFIG_INFO_4_DUAL_RCH_EN_SHFT		= 0x1f,
++	S_SWAY_CONFIG_INFO_4_RCH1_DEPTH_BMSK		= 0xff,
++	S_SWAY_CONFIG_INFO_4_RCH1_DEPTH_SHFT		= 0x0,
++};
++
++#define S_SWAY_CONFIG_INFO_5_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000070)
++enum bimc_s_sway_config_info_5 {
++	S_SWAY_CONFIG_INFO_5_RMSK			= 0x800000ff,
++	S_SWAY_CONFIG_INFO_5_QCH_EN_BMSK		= 0x80000000,
++	S_SWAY_CONFIG_INFO_5_QCH_EN_SHFT		= 0x1f,
++	S_SWAY_CONFIG_INFO_5_QCH_DEPTH_BMSK		= 0xff,
++	S_SWAY_CONFIG_INFO_5_QCH_DEPTH_SHFT		= 0x0,
++};
++
++#define S_SWAY_CONFIG_INFO_6_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000080)
++enum bimc_s_sway_config_info_6 {
++	S_SWAY_CONFIG_INFO_6_RMSK			= 0x1,
++	S_SWAY_CONFIG_INFO_6_S2SW_PIPELINE_EN_BMSK	= 0x1,
++	S_SWAY_CONFIG_INFO_6_S2SW_PIPELINE_EN_SHFT	= 0x0,
++};
++
++#define S_SWAY_INT_STATUS_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000100)
++enum bimc_s_sway_int_status {
++	S_SWAY_INT_STATUS_RMSK		= 0x3,
++	S_SWAY_INT_STATUS_RFU_BMSK	= 0x3,
++	S_SWAY_INT_STATUS_RFU_SHFT	= 0x0,
++};
++
++#define S_SWAY_INT_CLR_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000108)
++enum bimc_s_sway_int_clr {
++	S_SWAY_INT_CLR_RMSK		= 0x3,
++	S_SWAY_INT_CLR_RFU_BMSK		= 0x3,
++	S_SWAY_INT_CLR_RFU_SHFT		= 0x0,
++};
++
++
++#define S_SWAY_INT_EN_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x0000010c)
++enum bimc_s_sway_int_en {
++	S_SWAY_INT_EN_RMSK		= 0x3,
++	S_SWAY_INT_EN_RFU_BMSK		= 0x3,
++	S_SWAY_INT_EN_RFU_SHFT		= 0x0,
++};
++
++#define S_SWAY_CLK_CTRL_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000200)
++enum bimc_s_sway_clk_ctrl {
++	S_SWAY_CLK_CTRL_RMSK				= 0x3,
++	S_SWAY_CLK_CTRL_SLAVE_CLK_GATING_EN_BMSK	= 0x2,
++	S_SWAY_CLK_CTRL_SLAVE_CLK_GATING_EN_SHFT	= 0x1,
++	S_SWAY_CLK_CTRL_CORE_CLK_GATING_EN_BMSK		= 0x1,
++	S_SWAY_CLK_CTRL_CORE_CLK_GATING_EN_SHFT		= 0x0,
++};
++
++#define S_SWAY_RCH_SEL_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000210)
++enum bimc_s_sway_rch_sel {
++	S_SWAY_RCH_SEL_RMSK		= 0x7f,
++	S_SWAY_RCH_SEL_UNUSED_BMSK	= 0x7f,
++	S_SWAY_RCH_SEL_UNUSED_SHFT	= 0x0,
++};
++
++
++#define S_SWAY_MAX_OUTSTANDING_REQS_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000220)
++enum bimc_s_sway_max_outstanding_reqs {
++	S_SWAY_MAX_OUTSTANDING_REQS_RMSK	= 0xffff,
++	S_SWAY_MAX_OUTSTANDING_REQS_WRITE_BMSK	= 0xff00,
++	S_SWAY_MAX_OUTSTANDING_REQS_WRITE_SHFT	= 0x8,
++	S_SWAY_MAX_OUTSTANDING_REQS_READ_BMSK	= 0xff,
++	S_SWAY_MAX_OUTSTANDING_REQS_READ_SHFT	= 0x0,
++};
++
++
++#define S_SWAY_BUF_STATUS_0_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000400)
++enum bimc_s_sway_buf_status_0 {
++	S_SWAY_BUF_STATUS_0_RMSK			= 0xf0300f03,
++	S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_FULL_BMSK	= 0x80000000,
++	S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_FULL_SHFT	= 0x1f,
++	S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_EMPTY_BMSK	= 0x40000000,
++	S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_EMPTY_SHFT	= 0x1e,
++	S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_FULL_BMSK	= 0x20000000,
++	S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_FULL_SHFT	= 0x1d,
++	S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_EMPTY_BMSK	= 0x10000000,
++	S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_EMPTY_SHFT	= 0x1c,
++	S_SWAY_BUF_STATUS_0_BCH_RD_FULL_BMSK		= 0x200000,
++	S_SWAY_BUF_STATUS_0_BCH_RD_FULL_SHFT		= 0x15,
++	S_SWAY_BUF_STATUS_0_BCH_RD_EMPTY_BMSK		= 0x100000,
++	S_SWAY_BUF_STATUS_0_BCH_RD_EMPTY_SHFT		= 0x14,
++	S_SWAY_BUF_STATUS_0_WCH_DATA_WR_FULL_BMSK	= 0x800,
++	S_SWAY_BUF_STATUS_0_WCH_DATA_WR_FULL_SHFT	= 0xb,
++	S_SWAY_BUF_STATUS_0_WCH_DATA_WR_EMPTY_BMSK	= 0x400,
++	S_SWAY_BUF_STATUS_0_WCH_DATA_WR_EMPTY_SHFT	= 0xa,
++	S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_FULL_BMSK	= 0x200,
++	S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_FULL_SHFT	= 0x9,
++	S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_EMPTY_BMSK	= 0x100,
++	S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_EMPTY_SHFT	= 0x8,
++	S_SWAY_BUF_STATUS_0_ACH_WR_FULL_BMSK		= 0x2,
++	S_SWAY_BUF_STATUS_0_ACH_WR_FULL_SHFT		= 0x1,
++	S_SWAY_BUF_STATUS_0_ACH_WR_EMPTY_BMSK		= 0x1,
++	S_SWAY_BUF_STATUS_0_ACH_WR_EMPTY_SHFT		= 0x0,
++};
++
++#define S_SWAY_BUF_STATUS_1_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000410)
++enum bimc_s_sway_buf_status_1 {
++	S_SWAY_BUF_STATUS_1_RMSK			= 0xf0,
++	S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_FULL_BMSK	= 0x80,
++	S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_FULL_SHFT	= 0x7,
++	S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_EMPTY_BMSK	= 0x40,
++	S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_EMPTY_SHFT	= 0x6,
++	S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_FULL_BMSK	= 0x20,
++	S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_FULL_SHFT	= 0x5,
++	S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_EMPTY_BMSK	= 0x10,
++	S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_EMPTY_SHFT	= 0x4,
++};
++
++#define S_SWAY_BUF_STATUS_2_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000420)
++enum bimc_s_sway_buf_status_2 {
++	S_SWAY_BUF_STATUS_2_RMSK		= 0x30,
++	S_SWAY_BUF_STATUS_2_QCH_RD_FULL_BMSK	= 0x20,
++	S_SWAY_BUF_STATUS_2_QCH_RD_FULL_SHFT	= 0x5,
++	S_SWAY_BUF_STATUS_2_QCH_RD_EMPTY_BMSK	= 0x10,
++	S_SWAY_BUF_STATUS_2_QCH_RD_EMPTY_SHFT	= 0x4,
++};
++
++/* S_ARB_GENERIC */
++
++#define S_ARB_REG_BASE(b)	((b) + 0x00049000)
++
++#define S_ARB_COMPONENT_INFO_ADDR(b, n) \
++	(S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000000)
++enum bimc_s_arb_component_info {
++	S_ARB_COMPONENT_INFO_RMSK		= 0xffffff,
++	S_ARB_COMPONENT_INFO_INSTANCE_BMSK	= 0xff0000,
++	S_ARB_COMPONENT_INFO_INSTANCE_SHFT	= 0x10,
++	S_ARB_COMPONENT_INFO_SUB_TYPE_BMSK	= 0xff00,
++	S_ARB_COMPONENT_INFO_SUB_TYPE_SHFT	= 0x8,
++	S_ARB_COMPONENT_INFO_TYPE_BMSK		= 0xff,
++	S_ARB_COMPONENT_INFO_TYPE_SHFT		= 0x0,
++};
++
++#define S_ARB_CONFIG_INFO_0_ADDR(b, n) \
++		(S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000020)
++enum bimc_s_arb_config_info_0 {
++	S_ARB_CONFIG_INFO_0_RMSK			= 0x800000ff,
++	S_ARB_CONFIG_INFO_0_ARB2SW_PIPELINE_EN_BMSK	= 0x80000000,
++	S_ARB_CONFIG_INFO_0_ARB2SW_PIPELINE_EN_SHFT	= 0x1f,
++	S_ARB_CONFIG_INFO_0_FUNC_BMSK			= 0xff,
++	S_ARB_CONFIG_INFO_0_FUNC_SHFT			= 0x0,
++};
++
++#define S_ARB_CONFIG_INFO_1_ADDR(b, n) \
++		(S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000030)
++enum bimc_s_arb_config_info_1 {
++	S_ARB_CONFIG_INFO_1_RMSK			= 0xffffffff,
++	S_ARB_CONFIG_INFO_1_MPORT_CONNECTIVITY_BMSK	= 0xffffffff,
++	S_ARB_CONFIG_INFO_1_MPORT_CONNECTIVITY_SHFT	= 0x0,
++};
++
++#define S_ARB_CLK_CTRL_ADDR(b) \
++	(S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000200)
++enum bimc_s_arb_clk_ctrl {
++	S_ARB_CLK_CTRL_RMSK				= 0x1,
++	S_ARB_CLK_CTRL_SLAVE_CLK_GATING_EN_BMSK		= 0x2,
++	S_ARB_CLK_CTRL_SLAVE_CLK_GATING_EN_SHFT		= 0x1,
++	S_ARB_CLK_CTRL_CORE_CLK_GATING_EN_BMSK		= 0x1,
++	S_ARB_CLK_CTRL_CORE_CLK_GATING_EN_SHFT		= 0x0,
++	S_ARB_CLK_CTRL_CLK_GATING_EN_BMSK		= 0x1,
++	S_ARB_CLK_CTRL_CLK_GATING_EN_SHFT		= 0x0,
++};
++
++#define S_ARB_MODE_ADDR(b, n) \
++	(S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000210)
++enum bimc_s_arb_mode {
++	S_ARB_MODE_RMSK				= 0xf0000001,
++	S_ARB_MODE_WR_GRANTS_AHEAD_BMSK		= 0xf0000000,
++	S_ARB_MODE_WR_GRANTS_AHEAD_SHFT		= 0x1c,
++	S_ARB_MODE_PRIO_RR_EN_BMSK		= 0x1,
++	S_ARB_MODE_PRIO_RR_EN_SHFT		= 0x0,
++};
++
++#define BKE_HEALTH_MASK \
++	(M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK |\
++	M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK |\
++	M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK)
++
++#define BKE_HEALTH_VAL(limit, areq, plvl) \
++	((((limit) << M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_SHFT) & \
++	M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK) | \
++	(((areq) << M_BKE_HEALTH_0_CONFIG_AREQPRIO_SHFT) & \
++	M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK) | \
++	(((plvl) << M_BKE_HEALTH_0_CONFIG_PRIOLVL_SHFT) & \
++	M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK))
++
++#define MAX_GRANT_PERIOD \
++	(M_BKE_GP_GP_BMSK >> \
++	M_BKE_GP_GP_SHFT)
++
++#define MAX_GC \
++	(M_BKE_GC_GC_BMSK >> \
++	(M_BKE_GC_GC_SHFT + 1))
++
++static int bimc_div(int64_t *a, uint32_t b)
++{
++	if ((*a > 0) && (*a < b)) {
++		*a = 0;
++		return 1;
++	} else {
++		return do_div(*a, b);
++	}
++}
++
++#define ENABLE(val) ((val) == 1 ? 1 : 0)
++void msm_bus_bimc_set_mas_clk_gate(struct msm_bus_bimc_info *binfo,
++	uint32_t mas_index, struct msm_bus_bimc_clk_gate *bgate)
++{
++	uint32_t val, mask, reg_val;
++	void __iomem *addr;
++
++	reg_val = readl_relaxed(M_CLK_CTRL_ADDR(binfo->base,
++			mas_index)) & M_CLK_CTRL_RMSK;
++	addr = M_CLK_CTRL_ADDR(binfo->base, mas_index);
++	mask = (M_CLK_CTRL_MAS_CLK_GATING_EN_BMSK |
++		M_CLK_CTRL_CORE_CLK_GATING_EN_BMSK);
++	val = (bgate->core_clk_gate_en <<
++		M_CLK_CTRL_MAS_CLK_GATING_EN_SHFT) |
++		bgate->port_clk_gate_en;
++	writel_relaxed(((reg_val & (~mask)) | (val & mask)), addr);
++	/* Ensure clock gating enable mask is set before exiting */
++	wmb();
++}
++
++void msm_bus_bimc_arb_en(struct msm_bus_bimc_info *binfo,
++	uint32_t slv_index, bool en)
++{
++	uint32_t reg_val, reg_mask_val, enable, val;
++
++	reg_mask_val = (readl_relaxed(S_ARB_CONFIG_INFO_0_ADDR(binfo->
++		base, slv_index)) & S_ARB_CONFIG_INFO_0_FUNC_BMSK)
++		>> S_ARB_CONFIG_INFO_0_FUNC_SHFT;
++	enable = ENABLE(en);
++	val = enable << S_ARB_MODE_PRIO_RR_EN_SHFT;
++	if (reg_mask_val == BIMC_ARB_MODE_PRIORITY_RR) {
++		reg_val = readl_relaxed(S_ARB_CONFIG_INFO_0_ADDR(binfo->
++			base, slv_index)) & S_ARB_MODE_RMSK;
++		writel_relaxed(((reg_val & (~(S_ARB_MODE_PRIO_RR_EN_BMSK))) |
++			(val & S_ARB_MODE_PRIO_RR_EN_BMSK)),
++			S_ARB_MODE_ADDR(binfo->base, slv_index));
++		/* Ensure arbitration mode is set before returning */
++		wmb();
++	}
++}
++
++static void set_qos_mode(void __iomem *baddr, uint32_t index, uint32_t val0,
++	uint32_t val1, uint32_t val2)
++{
++	uint32_t reg_val, val;
++
++	reg_val = readl_relaxed(M_PRIOLVL_OVERRIDE_ADDR(baddr,
++		index)) & M_PRIOLVL_OVERRIDE_RMSK;
++	val = val0 << M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT;
++	writel_relaxed(((reg_val & ~(M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK))
++		| (val & M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK)),
++		M_PRIOLVL_OVERRIDE_ADDR(baddr, index));
++	reg_val = readl_relaxed(M_RD_CMD_OVERRIDE_ADDR(baddr, index)) &
++		M_RD_CMD_OVERRIDE_RMSK;
++	val = val1 << M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT;
++	writel_relaxed(((reg_val & ~(M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK
++		)) | (val & M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK)),
++		M_RD_CMD_OVERRIDE_ADDR(baddr, index));
++	reg_val = readl_relaxed(M_WR_CMD_OVERRIDE_ADDR(baddr, index)) &
++		M_WR_CMD_OVERRIDE_RMSK;
++	val = val2 << M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT;
++	writel_relaxed(((reg_val & ~(M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK
++		)) | (val & M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK)),
++		M_WR_CMD_OVERRIDE_ADDR(baddr, index));
++	/* Ensure the priority register writes go through */
++	wmb();
++}
++
++static void msm_bus_bimc_set_qos_mode(void __iomem *base,
++	uint32_t mas_index, uint8_t qmode_sel)
++{
++	uint32_t reg_val, val;
++
++	switch (qmode_sel) {
++	case BIMC_QOS_MODE_FIXED:
++		reg_val = readl_relaxed(M_BKE_EN_ADDR(base,
++			mas_index));
++		writel_relaxed((reg_val & (~M_BKE_EN_EN_BMSK)),
++			M_BKE_EN_ADDR(base, mas_index));
++		/* Ensure that the book-keeping register writes
++		 * go through before setting QoS mode.
++		 * QoS mode registers might write beyond 1K
++		 * boundary in future
++		 */
++		wmb();
++		set_qos_mode(base, mas_index, 1, 1, 1);
++		break;
++
++	case BIMC_QOS_MODE_BYPASS:
++		reg_val = readl_relaxed(M_BKE_EN_ADDR(base,
++			mas_index));
++		writel_relaxed((reg_val & (~M_BKE_EN_EN_BMSK)),
++			M_BKE_EN_ADDR(base, mas_index));
++		/* Ensure that the book-keeping register writes
++		 * go through before setting QoS mode.
++		 * QoS mode registers might write beyond 1K
++		 * boundary in future
++		 */
++		wmb();
++		set_qos_mode(base, mas_index, 0, 0, 0);
++		break;
++
++	case BIMC_QOS_MODE_REGULATOR:
++	case BIMC_QOS_MODE_LIMITER:
++		set_qos_mode(base, mas_index, 0, 0, 0);
++		reg_val = readl_relaxed(M_BKE_EN_ADDR(base,
++			mas_index));
++		val = 1 << M_BKE_EN_EN_SHFT;
++		/* Ensure that the book-keeping register writes
++		 * go through before setting QoS mode.
++		 * QoS mode registers might write beyond 1K
++		 * boundary in future
++		 */
++		wmb();
++		writel_relaxed(((reg_val & (~M_BKE_EN_EN_BMSK)) | (val &
++			M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(base,
++			mas_index));
++		break;
++	default:
++		break;
++	}
++}
++
++static void set_qos_prio_rl(void __iomem *addr, uint32_t rmsk,
++	uint8_t index, struct msm_bus_bimc_qos_mode *qmode)
++{
++	uint32_t reg_val, val0, val;
++
++	/* Note, addr is already passed with right mas_index */
++	reg_val = readl_relaxed(addr) & rmsk;
++	val0 = BKE_HEALTH_VAL(qmode->rl.qhealth[index].limit_commands,
++		qmode->rl.qhealth[index].areq_prio,
++		qmode->rl.qhealth[index].prio_level);
++	val = ((reg_val & (~(BKE_HEALTH_MASK))) | (val0 & BKE_HEALTH_MASK));
++	writel_relaxed(val, addr);
++	/* Ensure that priority for regulator/limiter modes are
++	 * set before returning
++	 */
++	wmb();
++
++}
++
++static void msm_bus_bimc_set_qos_prio(void __iomem *base,
++	uint32_t mas_index, uint8_t qmode_sel,
++	struct msm_bus_bimc_qos_mode *qmode)
++{
++	uint32_t reg_val, val;
++
++	switch (qmode_sel) {
++	case BIMC_QOS_MODE_FIXED:
++		reg_val = readl_relaxed(M_PRIOLVL_OVERRIDE_ADDR(
++			base, mas_index)) & M_PRIOLVL_OVERRIDE_RMSK;
++		val =  qmode->fixed.prio_level <<
++			M_PRIOLVL_OVERRIDE_SHFT;
++		writel_relaxed(((reg_val &
++			~(M_PRIOLVL_OVERRIDE_BMSK)) | (val
++			& M_PRIOLVL_OVERRIDE_BMSK)),
++			M_PRIOLVL_OVERRIDE_ADDR(base, mas_index));
++
++		reg_val = readl_relaxed(M_RD_CMD_OVERRIDE_ADDR(
++			base, mas_index)) & M_RD_CMD_OVERRIDE_RMSK;
++		val =  qmode->fixed.areq_prio_rd <<
++			M_RD_CMD_OVERRIDE_AREQPRIO_SHFT;
++		writel_relaxed(((reg_val & ~(M_RD_CMD_OVERRIDE_AREQPRIO_BMSK))
++			| (val & M_RD_CMD_OVERRIDE_AREQPRIO_BMSK)),
++			M_RD_CMD_OVERRIDE_ADDR(base, mas_index));
++
++		reg_val = readl_relaxed(M_WR_CMD_OVERRIDE_ADDR(
++			base, mas_index)) & M_WR_CMD_OVERRIDE_RMSK;
++		val =  qmode->fixed.areq_prio_wr <<
++			M_WR_CMD_OVERRIDE_AREQPRIO_SHFT;
++		writel_relaxed(((reg_val & ~(M_WR_CMD_OVERRIDE_AREQPRIO_BMSK))
++			| (val & M_WR_CMD_OVERRIDE_AREQPRIO_BMSK)),
++			M_WR_CMD_OVERRIDE_ADDR(base, mas_index));
++		/* Ensure that fixed mode register writes go through
++		 * before returning
++		 */
++		wmb();
++		break;
++
++	case BIMC_QOS_MODE_REGULATOR:
++	case BIMC_QOS_MODE_LIMITER:
++		set_qos_prio_rl(M_BKE_HEALTH_3_CONFIG_ADDR(base,
++			mas_index), M_BKE_HEALTH_3_CONFIG_RMSK, 3, qmode);
++		set_qos_prio_rl(M_BKE_HEALTH_2_CONFIG_ADDR(base,
++			mas_index), M_BKE_HEALTH_2_CONFIG_RMSK, 2, qmode);
++		set_qos_prio_rl(M_BKE_HEALTH_1_CONFIG_ADDR(base,
++			mas_index), M_BKE_HEALTH_1_CONFIG_RMSK, 1, qmode);
++		set_qos_prio_rl(M_BKE_HEALTH_0_CONFIG_ADDR(base,
++			mas_index), M_BKE_HEALTH_0_CONFIG_RMSK, 0 , qmode);
++		break;
++	case BIMC_QOS_MODE_BYPASS:
++	default:
++		break;
++	}
++}
++
++static void set_qos_bw_regs(void __iomem *baddr, uint32_t mas_index,
++	int32_t th, int32_t tm, int32_t tl, uint32_t gp,
++	uint32_t gc)
++{
++	int32_t reg_val, val;
++	int32_t bke_reg_val;
++	int16_t val2;
++
++	/* Disable BKE before writing to registers as per spec */
++	bke_reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index));
++	writel_relaxed((bke_reg_val & ~(M_BKE_EN_EN_BMSK)),
++		M_BKE_EN_ADDR(baddr, mas_index));
++
++	/* Write values of registers calculated */
++	reg_val = readl_relaxed(M_BKE_GP_ADDR(baddr, mas_index))
++		& M_BKE_GP_RMSK;
++	val =  gp << M_BKE_GP_GP_SHFT;
++	writel_relaxed(((reg_val & ~(M_BKE_GP_GP_BMSK)) | (val &
++		M_BKE_GP_GP_BMSK)), M_BKE_GP_ADDR(baddr, mas_index));
++
++	reg_val = readl_relaxed(M_BKE_GC_ADDR(baddr, mas_index)) &
++		M_BKE_GC_RMSK;
++	val =  gc << M_BKE_GC_GC_SHFT;
++	writel_relaxed(((reg_val & ~(M_BKE_GC_GC_BMSK)) | (val &
++		M_BKE_GC_GC_BMSK)), M_BKE_GC_ADDR(baddr, mas_index));
++
++	reg_val = readl_relaxed(M_BKE_THH_ADDR(baddr, mas_index)) &
++		M_BKE_THH_RMSK;
++	val =  th << M_BKE_THH_THRESH_SHFT;
++	writel_relaxed(((reg_val & ~(M_BKE_THH_THRESH_BMSK)) | (val &
++		M_BKE_THH_THRESH_BMSK)), M_BKE_THH_ADDR(baddr, mas_index));
++
++	reg_val = readl_relaxed(M_BKE_THM_ADDR(baddr, mas_index)) &
++		M_BKE_THM_RMSK;
++	val2 =	tm << M_BKE_THM_THRESH_SHFT;
++	writel_relaxed(((reg_val & ~(M_BKE_THM_THRESH_BMSK)) | (val2 &
++		M_BKE_THM_THRESH_BMSK)), M_BKE_THM_ADDR(baddr, mas_index));
++
++	reg_val = readl_relaxed(M_BKE_THL_ADDR(baddr, mas_index)) &
++		M_BKE_THL_RMSK;
++	val2 =	tl << M_BKE_THL_THRESH_SHFT;
++	writel_relaxed(((reg_val & ~(M_BKE_THL_THRESH_BMSK)) |
++		(val2 & M_BKE_THL_THRESH_BMSK)), M_BKE_THL_ADDR(baddr,
++		mas_index));
++
++	/* Ensure that all bandwidth register writes have completed
++	 * before returning
++	 */
++	wmb();
++}
++
++static void msm_bus_bimc_set_qos_bw(void __iomem *base, uint32_t qos_freq,
++	uint32_t mas_index, struct msm_bus_bimc_qos_bw *qbw)
++{
++	uint32_t bke_en;
++
++	/* Validate QOS Frequency */
++	if (qos_freq == 0) {
++		MSM_BUS_DBG("Zero frequency\n");
++		return;
++	}
++
++	/* Get enable bit for BKE before programming the period */
++	bke_en = (readl_relaxed(M_BKE_EN_ADDR(base, mas_index)) &
++		M_BKE_EN_EN_BMSK) >> M_BKE_EN_EN_SHFT;
++
++	/* Only calculate if there's a requested bandwidth and window */
++	if (qbw->bw && qbw->ws) {
++		int64_t th, tm, tl;
++		uint32_t gp, gc;
++		int64_t gp_nominal, gp_required, gp_calc, data, temp;
++		int64_t win = qbw->ws * qos_freq;
++		temp = win;
++		/*
++		 * Calculate nominal grant period defined by requested
++		 * window size.
++		 * Ceil this value to max grant period.
++		 */
++		bimc_div(&temp, 1000000);
++		gp_nominal = min_t(uint64_t, MAX_GRANT_PERIOD, temp);
++		/*
++		 * Calculate max window size, defined by bw request.
++		 * Units: (KHz, MB/s)
++		 */
++		gp_calc = MAX_GC * qos_freq * 1000;
++		gp_required = gp_calc;
++		bimc_div(&gp_required, qbw->bw);
++
++		/* User min of two grant periods */
++		gp = min_t(int64_t, gp_nominal, gp_required);
++
++		/* Calculate bandwith in grants and ceil. */
++		temp = qbw->bw * gp;
++		data = qos_freq * 1000;
++		bimc_div(&temp, data);
++		gc = min_t(int64_t, MAX_GC, temp);
++
++		/* Calculate thresholds */
++		th = qbw->bw - qbw->thh;
++		tm = qbw->bw - qbw->thm;
++		tl = qbw->bw - qbw->thl;
++
++		th = th * gp;
++		bimc_div(&th, data);
++		tm = tm * gp;
++		bimc_div(&tm, data);
++		tl = tl * gp;
++		bimc_div(&tl, data);
++
++		MSM_BUS_DBG("BIMC: BW: mas_index: %d, th: %llu tm: %llu\n",
++			mas_index, th, tm);
++		MSM_BUS_DBG("BIMC: tl: %llu gp:%u gc: %u bke_en: %u\n",
++			tl, gp, gc, bke_en);
++		set_qos_bw_regs(base, mas_index, th, tm, tl, gp, gc);
++	} else
++		/* Clear bandwidth registers */
++		set_qos_bw_regs(base, mas_index, 0, 0, 0, 0, 0);
++}
++
++static int msm_bus_bimc_allocate_commit_data(struct msm_bus_fabric_registration
++	*fab_pdata, void **cdata, int ctx)
++{
++	struct msm_bus_bimc_commit **cd = (struct msm_bus_bimc_commit **)cdata;
++	struct msm_bus_bimc_info *binfo =
++		(struct msm_bus_bimc_info *)fab_pdata->hw_data;
++
++	MSM_BUS_DBG("Allocating BIMC commit data\n");
++	*cd = kzalloc(sizeof(struct msm_bus_bimc_commit), GFP_KERNEL);
++	if (!*cd) {
++		MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
++		return -ENOMEM;
++	}
++
++	(*cd)->mas = binfo->cdata[ctx].mas;
++	(*cd)->slv = binfo->cdata[ctx].slv;
++
++	return 0;
++}
++
++static void *msm_bus_bimc_allocate_bimc_data(struct platform_device *pdev,
++	struct msm_bus_fabric_registration *fab_pdata)
++{
++	struct resource *bimc_mem;
++	struct resource *bimc_io;
++	struct msm_bus_bimc_info *binfo;
++	int i;
++
++	MSM_BUS_DBG("Allocating BIMC data\n");
++	binfo = kzalloc(sizeof(struct msm_bus_bimc_info), GFP_KERNEL);
++	if (!binfo) {
++		WARN(!binfo, "Couldn't alloc mem for bimc_info\n");
++		return NULL;
++	}
++
++	binfo->qos_freq = fab_pdata->qos_freq;
++
++	binfo->params.nmasters = fab_pdata->nmasters;
++	binfo->params.nslaves = fab_pdata->nslaves;
++	binfo->params.bus_id = fab_pdata->id;
++
++	for (i = 0; i < NUM_CTX; i++) {
++		binfo->cdata[i].mas = kzalloc(sizeof(struct
++			msm_bus_node_hw_info) * fab_pdata->nmasters * 2,
++			GFP_KERNEL);
++		if (!binfo->cdata[i].mas) {
++			MSM_BUS_ERR("Couldn't alloc mem for bimc master hw\n");
++			kfree(binfo);
++			return NULL;
++		}
++
++		binfo->cdata[i].slv = kzalloc(sizeof(struct
++			msm_bus_node_hw_info) * fab_pdata->nslaves * 2,
++			GFP_KERNEL);
++		if (!binfo->cdata[i].slv) {
++			MSM_BUS_DBG("Couldn't alloc mem for bimc slave hw\n");
++			kfree(binfo->cdata[i].mas);
++			kfree(binfo);
++			return NULL;
++		}
++	}
++
++	if (fab_pdata->virt) {
++		MSM_BUS_DBG("Don't get memory regions for virtual fabric\n");
++		goto skip_mem;
++	}
++
++	bimc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!bimc_mem) {
++		MSM_BUS_ERR("Cannot get BIMC Base address\n");
++		kfree(binfo);
++		return NULL;
++	}
++
++	bimc_io = request_mem_region(bimc_mem->start,
++			resource_size(bimc_mem), pdev->name);
++	if (!bimc_io) {
++		MSM_BUS_ERR("BIMC memory unavailable\n");
++		kfree(binfo);
++		return NULL;
++	}
++
++	binfo->base = ioremap(bimc_mem->start, resource_size(bimc_mem));
++	if (!binfo->base) {
++		MSM_BUS_ERR("IOremap failed for BIMC!\n");
++		release_mem_region(bimc_mem->start, resource_size(bimc_mem));
++		kfree(binfo);
++		return NULL;
++	}
++
++skip_mem:
++	fab_pdata->hw_data = (void *)binfo;
++	return (void *)binfo;
++}
++
++static void free_commit_data(void *cdata)
++{
++	struct msm_bus_bimc_commit *cd = (struct msm_bus_bimc_commit *)cdata;
++
++	kfree(cd->mas);
++	kfree(cd->slv);
++	kfree(cd);
++}
++
++static void bke_switch(
++	void __iomem *baddr, uint32_t mas_index, bool req, int mode)
++{
++	uint32_t reg_val, val, cur_val;
++
++	val = req << M_BKE_EN_EN_SHFT;
++	reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index));
++	cur_val = reg_val & M_BKE_EN_RMSK;
++	if (val == cur_val)
++		return;
++
++	if (!req && mode == BIMC_QOS_MODE_FIXED)
++		set_qos_mode(baddr, mas_index, 1, 1, 1);
++
++	writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (val &
++		M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(baddr, mas_index));
++	/* Make sure BKE on/off goes through before changing priorities */
++	wmb();
++
++	if (req)
++		set_qos_mode(baddr, mas_index, 0, 0, 0);
++}
++
++static void bimc_set_static_qos_bw(void __iomem *base, unsigned int qos_freq,
++	int mport, struct msm_bus_bimc_qos_bw *qbw)
++{
++	int32_t bw_mbps, thh = 0, thm, thl, gc;
++	int32_t gp;
++	u64 temp;
++
++	if (qos_freq == 0) {
++		MSM_BUS_DBG("No QoS Frequency.\n");
++		return;
++	}
++
++	if (!(qbw->bw && qbw->gp)) {
++		MSM_BUS_DBG("No QoS Bandwidth or Window size\n");
++		return;
++	}
++
++	/* Convert bandwidth to MBPS */
++	temp = qbw->bw;
++	bimc_div(&temp, 1000000);
++	bw_mbps = temp;
++
++	/* Grant period in clock cycles
++	 * Grant period from bandwidth structure
++	 * is in nano seconds, QoS freq is in KHz.
++	 * Divide by 1000 to get clock cycles.
++	 */
++	gp = (qos_freq * qbw->gp) / (1000 * NSEC_PER_USEC);
++
++	/* Grant count = BW in MBps * Grant period
++	 * in micro seconds
++	 */
++	gc = bw_mbps * (qbw->gp / NSEC_PER_USEC);
++	gc = min(gc, MAX_GC);
++
++	/* Medium threshold = -((Medium Threshold percentage *
++	 * Grant count) / 100)
++	 */
++	thm = -((qbw->thmp * gc) / 100);
++	qbw->thm = thm;
++
++	/* Low threshold = -(Grant count) */
++	thl = -gc;
++	qbw->thl = thl;
++
++	MSM_BUS_DBG("%s: BKE parameters: gp %d, gc %d, thm %d thl %d thh %d",
++			__func__, gp, gc, thm, thl, thh);
++
++	trace_bus_bke_params(gc, gp, thl, thm, thl);
++	set_qos_bw_regs(base, mport, thh, thm, thl, gp, gc);
++}
++
++static void msm_bus_bimc_config_master(
++	struct msm_bus_fabric_registration *fab_pdata,
++	struct msm_bus_inode_info *info,
++	uint64_t req_clk, uint64_t req_bw)
++{
++	int mode, i, ports;
++	struct msm_bus_bimc_info *binfo;
++	uint64_t bw = 0;
++
++	binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data;
++	ports = info->node_info->num_mports;
++
++	/**
++	 * Here check the details of dual configuration.
++	 * Take actions based on different modes.
++	 * Check for threshold if limiter mode, etc.
++	*/
++
++	if (req_clk <= info->node_info->th[0]) {
++		mode = info->node_info->mode;
++		bw = info->node_info->bimc_bw[0];
++	} else if ((info->node_info->num_thresh > 1) &&
++			(req_clk <= info->node_info->th[1])) {
++		mode = info->node_info->mode;
++		bw = info->node_info->bimc_bw[1];
++	} else
++		mode = info->node_info->mode_thresh;
++
++	switch (mode) {
++	case BIMC_QOS_MODE_BYPASS:
++	case BIMC_QOS_MODE_FIXED:
++		for (i = 0; i < ports; i++)
++			bke_switch(binfo->base, info->node_info->qport[i],
++				BKE_OFF, mode);
++		break;
++	case BIMC_QOS_MODE_REGULATOR:
++	case BIMC_QOS_MODE_LIMITER:
++		for (i = 0; i < ports; i++) {
++			/* If not in fixed mode, update bandwidth */
++			if ((info->node_info->cur_lim_bw != bw)
++					&& (mode != BIMC_QOS_MODE_FIXED)) {
++				struct msm_bus_bimc_qos_bw qbw;
++				qbw.ws = info->node_info->ws;
++				qbw.bw = bw;
++				qbw.gp = info->node_info->bimc_gp;
++				qbw.thmp = info->node_info->bimc_thmp;
++				bimc_set_static_qos_bw(binfo->base,
++					binfo->qos_freq,
++					info->node_info->qport[i], &qbw);
++				info->node_info->cur_lim_bw = bw;
++				MSM_BUS_DBG("%s: Qos is %d reqclk %llu bw %llu",
++						__func__, mode, req_clk, bw);
++			}
++			bke_switch(binfo->base, info->node_info->qport[i],
++				BKE_ON, mode);
++		}
++		break;
++	default:
++		break;
++	}
++}
++
++static void msm_bus_bimc_update_bw(struct msm_bus_inode_info *hop,
++	struct msm_bus_inode_info *info,
++	struct msm_bus_fabric_registration *fab_pdata,
++	void *sel_cdata, int *master_tiers,
++	int64_t add_bw)
++{
++	struct msm_bus_bimc_info *binfo;
++	struct msm_bus_bimc_qos_bw qbw;
++	int i;
++	int64_t bw;
++	int ports = info->node_info->num_mports;
++	struct msm_bus_bimc_commit *sel_cd =
++		(struct msm_bus_bimc_commit *)sel_cdata;
++
++	MSM_BUS_DBG("BIMC: Update bw for ID %d, with IID: %d: %lld\n",
++		info->node_info->id, info->node_info->priv_id, add_bw);
++
++	binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data;
++
++	if (info->node_info->num_mports == 0) {
++		MSM_BUS_DBG("BIMC: Skip Master BW\n");
++		goto skip_mas_bw;
++	}
++
++	ports = info->node_info->num_mports;
++	bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
++
++	for (i = 0; i < ports; i++) {
++		sel_cd->mas[info->node_info->masterp[i]].bw += bw;
++		sel_cd->mas[info->node_info->masterp[i]].hw_id =
++			info->node_info->mas_hw_id;
++		MSM_BUS_DBG("BIMC: Update mas_bw for ID: %d -> %llu\n",
++			info->node_info->priv_id,
++			sel_cd->mas[info->node_info->masterp[i]].bw);
++		if (info->node_info->hw_sel == MSM_BUS_RPM)
++			sel_cd->mas[info->node_info->masterp[i]].dirty = 1;
++		else {
++			if (!info->node_info->qport) {
++				MSM_BUS_DBG("No qos ports to update!\n");
++				break;
++			}
++			if (!(info->node_info->mode == BIMC_QOS_MODE_REGULATOR)
++					|| (info->node_info->mode ==
++						BIMC_QOS_MODE_LIMITER)) {
++				MSM_BUS_DBG("Skip QoS reg programming\n");
++				break;
++			}
++
++			MSM_BUS_DBG("qport: %d\n", info->node_info->qport[i]);
++			qbw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
++			qbw.ws = info->node_info->ws;
++			/* Threshold low = 90% of bw */
++			qbw.thl = div_s64((90 * bw), 100);
++			/* Threshold medium = bw */
++			qbw.thm = bw;
++			/* Threshold high = 10% more than bw */
++			qbw.thh = div_s64((110 * bw), 100);
++			/* Check if info is a shared master.
++			 * If it is, mark it dirty
++			 * If it isn't, then set QOS Bandwidth.
++			 * Also if dual-conf is set, don't program bw regs.
++			 **/
++			if (!info->node_info->dual_conf &&
++			((info->node_info->mode == BIMC_QOS_MODE_LIMITER) ||
++			(info->node_info->mode == BIMC_QOS_MODE_REGULATOR)))
++				msm_bus_bimc_set_qos_bw(binfo->base,
++					binfo->qos_freq,
++					info->node_info->qport[i], &qbw);
++		}
++	}
++
++skip_mas_bw:
++	ports = hop->node_info->num_sports;
++	MSM_BUS_DBG("BIMC: ID: %d, Sports: %d\n", hop->node_info->priv_id,
++		ports);
++
++	for (i = 0; i < ports; i++) {
++		sel_cd->slv[hop->node_info->slavep[i]].bw += add_bw;
++		sel_cd->slv[hop->node_info->slavep[i]].hw_id =
++			hop->node_info->slv_hw_id;
++		MSM_BUS_DBG("BIMC: Update slave_bw: ID: %d -> %llu\n",
++			hop->node_info->priv_id,
++			sel_cd->slv[hop->node_info->slavep[i]].bw);
++		MSM_BUS_DBG("BIMC: Update slave_bw: index: %d\n",
++			hop->node_info->slavep[i]);
++		/* Check if hop is a shared slave.
++		 * If it is, mark it dirty
++		 * If it isn't, then nothing to be done as the
++		 * slaves are in bypass mode.
++		 **/
++		if (hop->node_info->hw_sel == MSM_BUS_RPM) {
++			MSM_BUS_DBG("Slave dirty: %d, slavep: %d\n",
++				hop->node_info->priv_id,
++				hop->node_info->slavep[i]);
++			sel_cd->slv[hop->node_info->slavep[i]].dirty = 1;
++		}
++	}
++}
++
++static int msm_bus_bimc_commit(struct msm_bus_fabric_registration
++	*fab_pdata, void *hw_data, void **cdata)
++{
++	MSM_BUS_DBG("\nReached BIMC Commit\n");
++	msm_bus_remote_hw_commit(fab_pdata, hw_data, cdata);
++	return 0;
++}
++
++static void msm_bus_bimc_config_limiter(
++	struct msm_bus_fabric_registration *fab_pdata,
++	struct msm_bus_inode_info *info)
++{
++	struct msm_bus_bimc_info *binfo;
++	int mode, i, ports;
++
++	binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data;
++	ports = info->node_info->num_mports;
++
++	if (!info->node_info->qport) {
++		MSM_BUS_DBG("No QoS Ports to init\n");
++		return;
++	}
++
++	if (info->cur_lim_bw)
++		mode = BIMC_QOS_MODE_LIMITER;
++	else
++		mode = info->node_info->mode;
++
++	switch (mode) {
++	case BIMC_QOS_MODE_BYPASS:
++	case BIMC_QOS_MODE_FIXED:
++		for (i = 0; i < ports; i++)
++			bke_switch(binfo->base, info->node_info->qport[i],
++				BKE_OFF, mode);
++		break;
++	case BIMC_QOS_MODE_REGULATOR:
++	case BIMC_QOS_MODE_LIMITER:
++		if (info->cur_lim_bw != info->cur_prg_bw) {
++			MSM_BUS_DBG("Enabled BKE throttling node %d to %llu\n",
++				info->node_info->id, info->cur_lim_bw);
++			trace_bus_bimc_config_limiter(info->node_info->id,
++				info->cur_lim_bw);
++			for (i = 0; i < ports; i++) {
++				/* If not in fixed mode, update bandwidth */
++				struct msm_bus_bimc_qos_bw qbw;
++
++				qbw.ws = info->node_info->ws;
++				qbw.bw = info->cur_lim_bw;
++				qbw.gp = info->node_info->bimc_gp;
++				qbw.thmp = info->node_info->bimc_thmp;
++				bimc_set_static_qos_bw(binfo->base,
++					binfo->qos_freq,
++					info->node_info->qport[i], &qbw);
++				bke_switch(binfo->base,
++					info->node_info->qport[i],
++					BKE_ON, mode);
++				info->cur_prg_bw = qbw.bw;
++			}
++		}
++		break;
++	default:
++		break;
++	}
++}
++
++static void bimc_init_mas_reg(struct msm_bus_bimc_info *binfo,
++	struct msm_bus_inode_info *info,
++	struct msm_bus_bimc_qos_mode *qmode, int mode)
++{
++	int i;
++
++	switch (mode) {
++	case BIMC_QOS_MODE_FIXED:
++		qmode->fixed.prio_level = info->node_info->prio_lvl;
++		qmode->fixed.areq_prio_rd = info->node_info->prio_rd;
++		qmode->fixed.areq_prio_wr = info->node_info->prio_wr;
++		break;
++	case BIMC_QOS_MODE_LIMITER:
++		qmode->rl.qhealth[0].limit_commands = 1;
++		qmode->rl.qhealth[1].limit_commands = 0;
++		qmode->rl.qhealth[2].limit_commands = 0;
++		qmode->rl.qhealth[3].limit_commands = 0;
++		break;
++	default:
++		break;
++	}
++
++	if (!info->node_info->qport) {
++		MSM_BUS_DBG("No QoS Ports to init\n");
++		return;
++	}
++
++	for (i = 0; i < info->node_info->num_mports; i++) {
++		/* If not in bypass mode, update priority */
++		if (mode != BIMC_QOS_MODE_BYPASS) {
++			msm_bus_bimc_set_qos_prio(binfo->base,
++				info->node_info->
++				qport[i], mode, qmode);
++
++			/* If not in fixed mode, update bandwidth */
++			if (mode != BIMC_QOS_MODE_FIXED) {
++				struct msm_bus_bimc_qos_bw qbw;
++				qbw.ws = info->node_info->ws;
++				qbw.bw = info->node_info->bimc_bw[0];
++				qbw.gp = info->node_info->bimc_gp;
++				qbw.thmp = info->node_info->bimc_thmp;
++				bimc_set_static_qos_bw(binfo->base,
++					binfo->qos_freq,
++					info->node_info->qport[i], &qbw);
++			}
++		}
++
++		/* set mode */
++		msm_bus_bimc_set_qos_mode(binfo->base,
++					info->node_info->qport[i],
++					mode);
++	}
++}
++
++static void init_health_regs(struct msm_bus_bimc_info *binfo,
++				struct msm_bus_inode_info *info,
++				struct msm_bus_bimc_qos_mode *qmode,
++				int mode)
++{
++	int i;
++
++	if (mode == BIMC_QOS_MODE_LIMITER) {
++		qmode->rl.qhealth[0].limit_commands = 1;
++		qmode->rl.qhealth[1].limit_commands = 0;
++		qmode->rl.qhealth[2].limit_commands = 0;
++		qmode->rl.qhealth[3].limit_commands = 0;
++
++		if (!info->node_info->qport) {
++			MSM_BUS_DBG("No QoS Ports to init\n");
++			return;
++		}
++
++		for (i = 0; i < info->node_info->num_mports; i++) {
++			/* If not in bypass mode, update priority */
++			if (mode != BIMC_QOS_MODE_BYPASS)
++				msm_bus_bimc_set_qos_prio(binfo->base,
++				info->node_info->qport[i], mode, qmode);
++		}
++	}
++}
++
++
++static int msm_bus_bimc_mas_init(struct msm_bus_bimc_info *binfo,
++	struct msm_bus_inode_info *info)
++{
++	struct msm_bus_bimc_qos_mode *qmode;
++	qmode = kzalloc(sizeof(struct msm_bus_bimc_qos_mode),
++		GFP_KERNEL);
++	if (!qmode) {
++		MSM_BUS_WARN("Couldn't alloc prio data for node: %d\n",
++			info->node_info->id);
++		return -ENOMEM;
++	}
++
++	info->hw_data = (void *)qmode;
++
++	/**
++	 * If the master supports dual configuration,
++	 * configure registers for both modes
++	 */
++	if (info->node_info->dual_conf)
++		bimc_init_mas_reg(binfo, info, qmode,
++			info->node_info->mode_thresh);
++	else if (info->node_info->nr_lim)
++		init_health_regs(binfo, info, qmode, BIMC_QOS_MODE_LIMITER);
++
++	bimc_init_mas_reg(binfo, info, qmode, info->node_info->mode);
++	return 0;
++}
++
++static void msm_bus_bimc_node_init(void *hw_data,
++	struct msm_bus_inode_info *info)
++{
++	struct msm_bus_bimc_info *binfo =
++		(struct msm_bus_bimc_info *)hw_data;
++
++	if (!IS_SLAVE(info->node_info->priv_id) &&
++		(info->node_info->hw_sel != MSM_BUS_RPM))
++		msm_bus_bimc_mas_init(binfo, info);
++}
++
++static int msm_bus_bimc_port_halt(uint32_t haltid, uint8_t mport)
++{
++	return 0;
++}
++
++static int msm_bus_bimc_port_unhalt(uint32_t haltid, uint8_t mport)
++{
++	return 0;
++}
++
++static int msm_bus_bimc_limit_mport(struct msm_bus_node_device_type *info,
++				void __iomem *qos_base, uint32_t qos_off,
++				uint32_t qos_delta, uint32_t qos_freq,
++				bool enable_lim, u64 lim_bw)
++{
++	int mode;
++	int i;
++
++	if (ZERO_OR_NULL_PTR(info->node_info->qport)) {
++		MSM_BUS_DBG("No QoS Ports to limit\n");
++		return 0;
++	}
++
++	if (enable_lim && lim_bw) {
++		mode =  BIMC_QOS_MODE_LIMITER;
++
++		if (!info->node_info->lim_bw) {
++			struct msm_bus_bimc_qos_mode qmode;
++			qmode.rl.qhealth[0].limit_commands = 1;
++			qmode.rl.qhealth[1].limit_commands = 0;
++			qmode.rl.qhealth[2].limit_commands = 0;
++			qmode.rl.qhealth[3].limit_commands = 0;
++
++			for (i = 0; i < info->node_info->num_qports; i++) {
++				/* If not in bypass mode, update priority */
++				if (mode != BIMC_QOS_MODE_BYPASS)
++					msm_bus_bimc_set_qos_prio(qos_base,
++					info->node_info->qport[i], mode,
++					&qmode);
++			}
++		}
++
++		for (i = 0; i < info->node_info->num_qports; i++) {
++			struct msm_bus_bimc_qos_bw qbw;
++			/* If not in fixed mode, update bandwidth */
++			if ((info->node_info->lim_bw != lim_bw)) {
++				qbw.ws = info->node_info->qos_params.ws;
++				qbw.bw = lim_bw;
++				qbw.gp = info->node_info->qos_params.gp;
++				qbw.thmp = info->node_info->qos_params.thmp;
++				bimc_set_static_qos_bw(qos_base, qos_freq,
++					info->node_info->qport[i], &qbw);
++			}
++			bke_switch(qos_base, info->node_info->qport[i],
++				BKE_ON, mode);
++		}
++		info->node_info->lim_bw = lim_bw;
++	} else {
++		mode = info->node_info->qos_params.mode;
++		for (i = 0; i < info->node_info->num_qports; i++) {
++			bke_switch(qos_base, info->node_info->qport[i],
++				BKE_OFF, mode);
++		}
++	}
++	info->node_info->qos_params.cur_mode = mode;
++	return 0;
++}
++
++static bool msm_bus_bimc_update_bw_reg(int mode)
++{
++	bool ret = false;
++
++	if ((mode == BIMC_QOS_MODE_LIMITER)
++		|| (mode == BIMC_QOS_MODE_REGULATOR))
++		ret = true;
++
++	return ret;
++}
++
++static int msm_bus_bimc_qos_init(struct msm_bus_node_device_type *info,
++				void __iomem *qos_base,
++				uint32_t qos_off, uint32_t qos_delta,
++				uint32_t qos_freq)
++{
++	int i;
++	struct msm_bus_bimc_qos_mode qmode;
++
++	switch (info->node_info->qos_params.mode) {
++	case BIMC_QOS_MODE_FIXED:
++		qmode.fixed.prio_level = info->node_info->qos_params.prio_lvl;
++		qmode.fixed.areq_prio_rd = info->node_info->qos_params.prio_rd;
++		qmode.fixed.areq_prio_wr = info->node_info->qos_params.prio_wr;
++		break;
++	case BIMC_QOS_MODE_LIMITER:
++		qmode.rl.qhealth[0].limit_commands = 1;
++		qmode.rl.qhealth[1].limit_commands = 0;
++		qmode.rl.qhealth[2].limit_commands = 0;
++		qmode.rl.qhealth[3].limit_commands = 0;
++		break;
++	default:
++		break;
++	}
++
++	if (ZERO_OR_NULL_PTR(info->node_info->qport)) {
++		MSM_BUS_DBG("No QoS Ports to init\n");
++		return 0;
++	}
++
++	for (i = 0; i < info->node_info->num_qports; i++) {
++		/* If not in bypass mode, update priority */
++		if (info->node_info->qos_params.mode != BIMC_QOS_MODE_BYPASS)
++			msm_bus_bimc_set_qos_prio(qos_base, info->node_info->
++				qport[i], info->node_info->qos_params.mode,
++									&qmode);
++
++		/* set mode */
++		if (info->node_info->qos_params.mode == BIMC_QOS_MODE_LIMITER)
++			bke_switch(qos_base, info->node_info->qport[i],
++				BKE_OFF, BIMC_QOS_MODE_FIXED);
++		else
++		       msm_bus_bimc_set_qos_mode(qos_base,
++				info->node_info->qport[i],
++				info->node_info->qos_params.mode);
++	}
++
++	return 0;
++}
++
++static int msm_bus_bimc_set_bw(struct msm_bus_node_device_type *dev,
++				void __iomem *qos_base, uint32_t qos_off,
++				uint32_t qos_delta, uint32_t qos_freq)
++{
++	struct msm_bus_bimc_qos_bw qbw;
++	int i;
++	int64_t bw = 0;
++	int ret = 0;
++	struct msm_bus_node_info_type *info = dev->node_info;
++
++	if (info && info->num_qports &&
++		((info->qos_params.mode == BIMC_QOS_MODE_LIMITER) ||
++		(info->qos_params.mode == BIMC_QOS_MODE_REGULATOR))) {
++		bw = msm_bus_div64(info->num_qports,
++				dev->node_ab.ab[DUAL_CTX]);
++
++		for (i = 0; i < info->num_qports; i++) {
++			MSM_BUS_DBG("BIMC: Update mas_bw for ID: %d -> %llu\n",
++				info->id, bw);
++
++			if (!info->qport) {
++				MSM_BUS_DBG("No qos ports to update!\n");
++				break;
++			}
++
++			qbw.bw = bw + info->qos_params.bw_buffer;
++			trace_bus_bimc_config_limiter(info->id, bw);
++
++			/* Default to gp of 5us */
++			qbw.gp = (info->qos_params.gp ?
++					info->qos_params.gp : 5000);
++			/* Default to thmp of 50% */
++			qbw.thmp = (info->qos_params.thmp ?
++					info->qos_params.thmp : 50);
++			/*
++			 * If the BW vote is 0 then set the QoS mode to
++			 * Fixed.
++			 */
++			if (bw) {
++				bimc_set_static_qos_bw(qos_base, qos_freq,
++					info->qport[i], &qbw);
++				bke_switch(qos_base, info->qport[i],
++					BKE_ON, info->qos_params.mode);
++			} else {
++				bke_switch(qos_base, info->qport[i],
++					BKE_OFF, BIMC_QOS_MODE_FIXED);
++			}
++		}
++	}
++	return ret;
++}
++
++int msm_bus_bimc_hw_init(struct msm_bus_fabric_registration *pdata,
++	struct msm_bus_hw_algorithm *hw_algo)
++{
++	/* Set interleaving to true by default */
++	MSM_BUS_DBG("\nInitializing BIMC...\n");
++	pdata->il_flag = true;
++	hw_algo->allocate_commit_data = msm_bus_bimc_allocate_commit_data;
++	hw_algo->allocate_hw_data = msm_bus_bimc_allocate_bimc_data;
++	hw_algo->node_init = msm_bus_bimc_node_init;
++	hw_algo->free_commit_data = free_commit_data;
++	hw_algo->update_bw = msm_bus_bimc_update_bw;
++	hw_algo->commit = msm_bus_bimc_commit;
++	hw_algo->port_halt = msm_bus_bimc_port_halt;
++	hw_algo->port_unhalt = msm_bus_bimc_port_unhalt;
++	hw_algo->config_master = msm_bus_bimc_config_master;
++	hw_algo->config_limiter = msm_bus_bimc_config_limiter;
++	hw_algo->update_bw_reg = msm_bus_bimc_update_bw_reg;
++	/* BIMC slaves are shared. Slave registers are set through RPM */
++	if (!pdata->ahb)
++		pdata->rpm_enabled = 1;
++	return 0;
++}
++
++int msm_bus_bimc_set_ops(struct msm_bus_node_device_type *bus_dev)
++{
++	if (!bus_dev)
++		return -ENODEV;
++	else {
++		bus_dev->fabdev->noc_ops.qos_init = msm_bus_bimc_qos_init;
++		bus_dev->fabdev->noc_ops.set_bw = msm_bus_bimc_set_bw;
++		bus_dev->fabdev->noc_ops.limit_mport = msm_bus_bimc_limit_mport;
++		bus_dev->fabdev->noc_ops.update_bw_reg =
++						msm_bus_bimc_update_bw_reg;
++	}
++	return 0;
++}
++EXPORT_SYMBOL(msm_bus_bimc_set_ops);
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_bimc.h
+@@ -0,0 +1,127 @@
++/* Copyright (c) 2012-2013, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _ARCH_ARM_MACH_MSM_BUS_BIMC_H
++#define _ARCH_ARM_MACH_MSM_BUS_BIMC_H
++
++struct msm_bus_bimc_params {
++	uint32_t bus_id;
++	uint32_t addr_width;
++	uint32_t data_width;
++	uint32_t nmasters;
++	uint32_t nslaves;
++};
++
++struct msm_bus_bimc_commit {
++	struct msm_bus_node_hw_info *mas;
++	struct msm_bus_node_hw_info *slv;
++};
++
++struct msm_bus_bimc_info {
++	void __iomem *base;
++	uint32_t base_addr;
++	uint32_t qos_freq;
++	struct msm_bus_bimc_params params;
++	struct msm_bus_bimc_commit cdata[NUM_CTX];
++};
++
++struct msm_bus_bimc_node {
++	uint32_t conn_mask;
++	uint32_t data_width;
++	uint8_t slv_arb_mode;
++};
++
++enum msm_bus_bimc_arb_mode {
++	BIMC_ARB_MODE_RR = 0,
++	BIMC_ARB_MODE_PRIORITY_RR,
++	BIMC_ARB_MODE_TIERED_RR,
++};
++
++
++enum msm_bus_bimc_interleave {
++	BIMC_INTERLEAVE_NONE = 0,
++	BIMC_INTERLEAVE_ODD,
++	BIMC_INTERLEAVE_EVEN,
++};
++
++struct msm_bus_bimc_slave_seg {
++	bool enable;
++	uint64_t start_addr;
++	uint64_t seg_size;
++	uint8_t interleave;
++};
++
++enum msm_bus_bimc_qos_mode_type {
++	BIMC_QOS_MODE_FIXED = 0,
++	BIMC_QOS_MODE_LIMITER,
++	BIMC_QOS_MODE_BYPASS,
++	BIMC_QOS_MODE_REGULATOR,
++};
++
++struct msm_bus_bimc_qos_health {
++	bool limit_commands;
++	uint32_t areq_prio;
++	uint32_t prio_level;
++};
++
++struct msm_bus_bimc_mode_fixed {
++	uint32_t prio_level;
++	uint32_t areq_prio_rd;
++	uint32_t areq_prio_wr;
++};
++
++struct msm_bus_bimc_mode_rl {
++	uint8_t qhealthnum;
++	struct msm_bus_bimc_qos_health qhealth[4];
++};
++
++struct msm_bus_bimc_qos_mode {
++	uint8_t mode;
++	struct msm_bus_bimc_mode_fixed fixed;
++	struct msm_bus_bimc_mode_rl rl;
++};
++
++struct msm_bus_bimc_qos_bw {
++	uint64_t bw;	/* bw is in Bytes/sec */
++	uint32_t ws;	/* Window size in nano seconds*/
++	int64_t thh;	/* Threshold high, bytes per second */
++	int64_t thm;	/* Threshold medium, bytes per second */
++	int64_t thl;	/* Threshold low, bytes per second */
++	u32 gp;	/* Grant Period in micro seconds */
++	u32 thmp; /* Threshold medium in percentage */
++};
++
++struct msm_bus_bimc_clk_gate {
++	bool core_clk_gate_en;
++	bool arb_clk_gate_en;	/* For arbiter */
++	bool port_clk_gate_en;	/* For regs on BIMC core clock */
++};
++
++void msm_bus_bimc_set_slave_seg(struct msm_bus_bimc_info *binfo,
++	uint32_t slv_index, uint32_t seg_index,
++	struct msm_bus_bimc_slave_seg *bsseg);
++void msm_bus_bimc_set_slave_clk_gate(struct msm_bus_bimc_info *binfo,
++	uint32_t slv_index, struct msm_bus_bimc_clk_gate *bgate);
++void msm_bus_bimc_set_mas_clk_gate(struct msm_bus_bimc_info *binfo,
++	uint32_t mas_index, struct msm_bus_bimc_clk_gate *bgate);
++void msm_bus_bimc_arb_en(struct msm_bus_bimc_info *binfo,
++	uint32_t slv_index, bool en);
++void msm_bus_bimc_get_params(struct msm_bus_bimc_info *binfo,
++	struct msm_bus_bimc_params *params);
++void msm_bus_bimc_get_mas_params(struct msm_bus_bimc_info *binfo,
++	uint32_t mas_index, struct msm_bus_bimc_node *mparams);
++void msm_bus_bimc_get_slv_params(struct msm_bus_bimc_info *binfo,
++	uint32_t slv_index, struct msm_bus_bimc_node *sparams);
++bool msm_bus_bimc_get_arb_en(struct msm_bus_bimc_info *binfo,
++	uint32_t slv_index);
++
++#endif /*_ARCH_ARM_MACH_MSM_BUS_BIMC_H*/
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_client_api.c
+@@ -0,0 +1,83 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/mutex.h>
++#include <linux/radix-tree.h>
++#include <linux/clk.h>
++#include "msm-bus.h"
++#include "msm_bus_core.h"
++
++struct msm_bus_arb_ops arb_ops;
++
++/**
++ * msm_bus_scale_register_client() - Register the clients with the msm bus
++ * driver
++ * @pdata: Platform data of the client, containing src, dest, ab, ib.
++ * Return non-zero value in case of success, 0 in case of failure.
++ *
++ * Client data contains the vectors specifying arbitrated bandwidth (ab)
++ * and instantaneous bandwidth (ib) requested between a particular
++ * src and dest.
++ */
++uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata)
++{
++	if (arb_ops.register_client)
++		return arb_ops.register_client(pdata);
++	else {
++		pr_err("%s: Bus driver not ready.",
++				__func__);
++		return 0;
++	}
++}
++EXPORT_SYMBOL(msm_bus_scale_register_client);
++
++/**
++ * msm_bus_scale_client_update_request() - Update the request for bandwidth
++ * from a particular client
++ *
++ * cl: Handle to the client
++ * index: Index into the vector, to which the bw and clock values need to be
++ * updated
++ */
++int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index)
++{
++	if (arb_ops.update_request)
++		return arb_ops.update_request(cl, index);
++	else {
++		pr_err("%s: Bus driver not ready.",
++				__func__);
++		return -EPROBE_DEFER;
++	}
++}
++EXPORT_SYMBOL(msm_bus_scale_client_update_request);
++
++/**
++ * msm_bus_scale_unregister_client() - Unregister the client from the bus driver
++ * @cl: Handle to the client
++ */
++void msm_bus_scale_unregister_client(uint32_t cl)
++{
++	if (arb_ops.unregister_client)
++		arb_ops.unregister_client(cl);
++	else {
++		pr_err("%s: Bus driver not ready.",
++				__func__);
++	}
++}
++EXPORT_SYMBOL(msm_bus_scale_unregister_client);
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_core.c
+@@ -0,0 +1,125 @@
++/* Copyright (c) 2010-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/mutex.h>
++#include <linux/radix-tree.h>
++#include <linux/clk.h>
++#include "msm-bus-board.h"
++#include "msm-bus.h"
++#include "msm_bus_core.h"
++
++static atomic_t num_fab = ATOMIC_INIT(0);
++
++int msm_bus_get_num_fab(void)
++{
++	return atomic_read(&num_fab);
++}
++
++int msm_bus_device_match(struct device *dev, void *id)
++{
++	struct msm_bus_fabric_device *fabdev = to_msm_bus_fabric_device(dev);
++
++	if (!fabdev) {
++		MSM_BUS_WARN("Fabric %p returning 0\n", fabdev);
++		return 0;
++	}
++	return fabdev->id == *(int *)id;
++}
++
++static void msm_bus_release(struct device *device)
++{
++}
++
++struct bus_type msm_bus_type = {
++	.name      = "msm-bus-type",
++};
++EXPORT_SYMBOL(msm_bus_type);
++
++/**
++ * msm_bus_get_fabric_device() - This function is used to search for
++ * the fabric device on the bus
++ * @fabid: Fabric id
++ * Function returns: Pointer to the fabric device
++ */
++struct msm_bus_fabric_device *msm_bus_get_fabric_device(int fabid)
++{
++	struct device *dev;
++	struct msm_bus_fabric_device *fabric;
++	dev = bus_find_device(&msm_bus_type, NULL, (void *)&fabid,
++		msm_bus_device_match);
++	if (!dev)
++		return NULL;
++	fabric = to_msm_bus_fabric_device(dev);
++	return fabric;
++}
++
++/**
++ * msm_bus_fabric_device_register() - Registers a fabric on msm bus
++ * @fabdev: Fabric device to be registered
++ */
++int msm_bus_fabric_device_register(struct msm_bus_fabric_device *fabdev)
++{
++	int ret = 0;
++	fabdev->dev.bus = &msm_bus_type;
++	fabdev->dev.release = msm_bus_release;
++	ret = dev_set_name(&fabdev->dev, fabdev->name);
++	if (ret) {
++		MSM_BUS_ERR("error setting dev name\n");
++		goto err;
++	}
++
++	ret = device_register(&fabdev->dev);
++	if (ret < 0) {
++		MSM_BUS_ERR("error registering device%d %s\n",
++				ret, fabdev->name);
++		goto err;
++	}
++	atomic_inc(&num_fab);
++err:
++	return ret;
++}
++
++/**
++ * msm_bus_fabric_device_unregister() - Unregisters the fabric
++ * devices from the msm bus
++ */
++void msm_bus_fabric_device_unregister(struct msm_bus_fabric_device *fabdev)
++{
++	device_unregister(&fabdev->dev);
++	atomic_dec(&num_fab);
++}
++
++static void __exit msm_bus_exit(void)
++{
++	bus_unregister(&msm_bus_type);
++}
++
++static int __init msm_bus_init(void)
++{
++	int retval = 0;
++	retval = bus_register(&msm_bus_type);
++	if (retval)
++		MSM_BUS_ERR("bus_register error! %d\n",
++			retval);
++	return retval;
++}
++postcore_initcall(msm_bus_init);
++module_exit(msm_bus_exit);
++MODULE_LICENSE("GPL v2");
++MODULE_VERSION("0.2");
++MODULE_ALIAS("platform:msm_bus");
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_core.h
+@@ -0,0 +1,375 @@
++/* Copyright (c) 2011-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _ARCH_ARM_MACH_MSM_BUS_CORE_H
++#define _ARCH_ARM_MACH_MSM_BUS_CORE_H
++
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/radix-tree.h>
++#include <linux/platform_device.h>
++#include "msm-bus-board.h"
++#include "msm-bus.h"
++
++#define MSM_BUS_DBG(msg, ...) \
++	pr_debug(msg, ## __VA_ARGS__)
++#define MSM_BUS_ERR(msg, ...) \
++	pr_err(msg, ## __VA_ARGS__)
++#define MSM_BUS_WARN(msg, ...) \
++	pr_warn(msg, ## __VA_ARGS__)
++#define MSM_FAB_ERR(msg, ...) \
++	dev_err(&fabric->fabdev.dev, msg, ## __VA_ARGS__)
++
++#define IS_MASTER_VALID(mas) \
++	(((mas >= MSM_BUS_MASTER_FIRST) && (mas <= MSM_BUS_MASTER_LAST)) \
++	 ? 1 : 0)
++#define IS_SLAVE_VALID(slv) \
++	(((slv >= MSM_BUS_SLAVE_FIRST) && (slv <= MSM_BUS_SLAVE_LAST)) ? 1 : 0)
++
++#define INTERLEAVED_BW(fab_pdata, bw, ports) \
++	((fab_pdata->il_flag) ? ((bw < 0) \
++	? -msm_bus_div64((ports), (-bw)) : msm_bus_div64((ports), (bw))) : (bw))
++#define INTERLEAVED_VAL(fab_pdata, n) \
++	((fab_pdata->il_flag) ? (n) : 1)
++#define KBTOB(a) (a * 1000ULL)
++
++enum msm_bus_dbg_op_type {
++	MSM_BUS_DBG_UNREGISTER = -2,
++	MSM_BUS_DBG_REGISTER,
++	MSM_BUS_DBG_OP = 1,
++};
++
++enum msm_bus_hw_sel {
++	MSM_BUS_RPM = 0,
++	MSM_BUS_NOC,
++	MSM_BUS_BIMC,
++};
++
++struct msm_bus_arb_ops {
++	uint32_t (*register_client)(struct msm_bus_scale_pdata *pdata);
++	int (*update_request)(uint32_t cl, unsigned int index);
++	void (*unregister_client)(uint32_t cl);
++};
++
++enum {
++	SLAVE_NODE,
++	MASTER_NODE,
++	CLK_NODE,
++	NR_LIM_NODE,
++};
++
++
++extern struct bus_type msm_bus_type;
++extern struct msm_bus_arb_ops arb_ops;
++extern void msm_bus_arb_setops_legacy(struct msm_bus_arb_ops *arb_ops);
++
++struct msm_bus_node_info {
++	unsigned int id;
++	unsigned int priv_id;
++	unsigned int mas_hw_id;
++	unsigned int slv_hw_id;
++	int gateway;
++	int *masterp;
++	int *qport;
++	int num_mports;
++	int *slavep;
++	int num_sports;
++	int *tier;
++	int num_tiers;
++	int ahb;
++	int hw_sel;
++	const char *slaveclk[NUM_CTX];
++	const char *memclk[NUM_CTX];
++	const char *iface_clk_node;
++	unsigned int buswidth;
++	unsigned int ws;
++	unsigned int mode;
++	unsigned int perm_mode;
++	unsigned int prio_lvl;
++	unsigned int prio_rd;
++	unsigned int prio_wr;
++	unsigned int prio1;
++	unsigned int prio0;
++	unsigned int num_thresh;
++	u64 *th;
++	u64 cur_lim_bw;
++	unsigned int mode_thresh;
++	bool dual_conf;
++	u64 *bimc_bw;
++	bool nr_lim;
++	u32 ff;
++	bool rt_mas;
++	u32 bimc_gp;
++	u32 bimc_thmp;
++	u64 floor_bw;
++	const char *name;
++};
++
++struct path_node {
++	uint64_t clk[NUM_CTX];
++	uint64_t bw[NUM_CTX];
++	uint64_t *sel_clk;
++	uint64_t *sel_bw;
++	int next;
++};
++
++struct msm_bus_link_info {
++	uint64_t clk[NUM_CTX];
++	uint64_t *sel_clk;
++	uint64_t memclk;
++	int64_t bw[NUM_CTX];
++	int64_t *sel_bw;
++	int *tier;
++	int num_tiers;
++};
++
++struct nodeclk {
++	struct clk *clk;
++	uint64_t rate;
++	bool dirty;
++	bool enable;
++};
++
++struct msm_bus_inode_info {
++	struct msm_bus_node_info *node_info;
++	uint64_t max_bw;
++	uint64_t max_clk;
++	uint64_t cur_lim_bw;
++	uint64_t cur_prg_bw;
++	struct msm_bus_link_info link_info;
++	int num_pnodes;
++	struct path_node *pnode;
++	int commit_index;
++	struct nodeclk nodeclk[NUM_CTX];
++	struct nodeclk memclk[NUM_CTX];
++	struct nodeclk iface_clk;
++	void *hw_data;
++};
++
++struct msm_bus_node_hw_info {
++	bool dirty;
++	unsigned int hw_id;
++	uint64_t bw;
++};
++
++struct msm_bus_hw_algorithm {
++	int (*allocate_commit_data)(struct msm_bus_fabric_registration
++		*fab_pdata, void **cdata, int ctx);
++	void *(*allocate_hw_data)(struct platform_device *pdev,
++		struct msm_bus_fabric_registration *fab_pdata);
++	void (*node_init)(void *hw_data, struct msm_bus_inode_info *info);
++	void (*free_commit_data)(void *cdata);
++	void (*update_bw)(struct msm_bus_inode_info *hop,
++		struct msm_bus_inode_info *info,
++		struct msm_bus_fabric_registration *fab_pdata,
++		void *sel_cdata, int *master_tiers,
++		int64_t add_bw);
++	void (*fill_cdata_buffer)(int *curr, char *buf, const int max_size,
++		void *cdata, int nmasters, int nslaves, int ntslaves);
++	int (*commit)(struct msm_bus_fabric_registration
++		*fab_pdata, void *hw_data, void **cdata);
++	int (*port_unhalt)(uint32_t haltid, uint8_t mport);
++	int (*port_halt)(uint32_t haltid, uint8_t mport);
++	void (*config_master)(struct msm_bus_fabric_registration *fab_pdata,
++		struct msm_bus_inode_info *info,
++		uint64_t req_clk, uint64_t req_bw);
++	void (*config_limiter)(struct msm_bus_fabric_registration *fab_pdata,
++		struct msm_bus_inode_info *info);
++	bool (*update_bw_reg)(int mode);
++};
++
++struct msm_bus_fabric_device {
++	int id;
++	const char *name;
++	struct device dev;
++	const struct msm_bus_fab_algorithm *algo;
++	const struct msm_bus_board_algorithm *board_algo;
++	struct msm_bus_hw_algorithm hw_algo;
++	int visited;
++	int num_nr_lim;
++	u64 nr_lim_thresh;
++	u32 eff_fact;
++};
++#define to_msm_bus_fabric_device(d) container_of(d, \
++		struct msm_bus_fabric_device, d)
++
++struct msm_bus_fabric {
++	struct msm_bus_fabric_device fabdev;
++	int ahb;
++	void *cdata[NUM_CTX];
++	bool arb_dirty;
++	bool clk_dirty;
++	struct radix_tree_root fab_tree;
++	int num_nodes;
++	struct list_head gateways;
++	struct msm_bus_inode_info info;
++	struct msm_bus_fabric_registration *pdata;
++	void *hw_data;
++};
++#define to_msm_bus_fabric(d) container_of(d, \
++	struct msm_bus_fabric, d)
++
++
++struct msm_bus_fab_algorithm {
++	int (*update_clks)(struct msm_bus_fabric_device *fabdev,
++		struct msm_bus_inode_info *pme, int index,
++		uint64_t curr_clk, uint64_t req_clk,
++		uint64_t bwsum, int flag, int ctx,
++		unsigned int cl_active_flag);
++	int (*port_halt)(struct msm_bus_fabric_device *fabdev, int portid);
++	int (*port_unhalt)(struct msm_bus_fabric_device *fabdev, int portid);
++	int (*commit)(struct msm_bus_fabric_device *fabdev);
++	struct msm_bus_inode_info *(*find_node)(struct msm_bus_fabric_device
++		*fabdev, int id);
++	struct msm_bus_inode_info *(*find_gw_node)(struct msm_bus_fabric_device
++		*fabdev, int id);
++	struct list_head *(*get_gw_list)(struct msm_bus_fabric_device *fabdev);
++	void (*update_bw)(struct msm_bus_fabric_device *fabdev, struct
++		msm_bus_inode_info * hop, struct msm_bus_inode_info *info,
++		int64_t add_bw, int *master_tiers, int ctx);
++	void (*config_master)(struct msm_bus_fabric_device *fabdev,
++		struct msm_bus_inode_info *info, uint64_t req_clk,
++		uint64_t req_bw);
++	void (*config_limiter)(struct msm_bus_fabric_device *fabdev,
++		struct msm_bus_inode_info *info);
++};
++
++struct msm_bus_board_algorithm {
++	int board_nfab;
++	void (*assign_iids)(struct msm_bus_fabric_registration *fabreg,
++		int fabid);
++	int (*get_iid)(int id);
++};
++
++/**
++ * Used to store the list of fabrics and other info to be
++ * maintained outside the fabric structure.
++ * Used while calculating path, and to find fabric ptrs
++ */
++struct msm_bus_fabnodeinfo {
++	struct list_head list;
++	struct msm_bus_inode_info *info;
++};
++
++struct msm_bus_client {
++	int id;
++	struct msm_bus_scale_pdata *pdata;
++	int *src_pnode;
++	int curr;
++};
++
++uint64_t msm_bus_div64(unsigned int width, uint64_t bw);
++int msm_bus_fabric_device_register(struct msm_bus_fabric_device *fabric);
++void msm_bus_fabric_device_unregister(struct msm_bus_fabric_device *fabric);
++struct msm_bus_fabric_device *msm_bus_get_fabric_device(int fabid);
++int msm_bus_get_num_fab(void);
++
++
++int msm_bus_hw_fab_init(struct msm_bus_fabric_registration *pdata,
++	struct msm_bus_hw_algorithm *hw_algo);
++void msm_bus_board_init(struct msm_bus_fabric_registration *pdata);
++void msm_bus_board_set_nfab(struct msm_bus_fabric_registration *pdata,
++	int nfab);
++#if defined(CONFIG_MSM_RPM_SMD)
++int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
++	struct msm_bus_hw_algorithm *hw_algo);
++int msm_bus_remote_hw_commit(struct msm_bus_fabric_registration
++	*fab_pdata, void *hw_data, void **cdata);
++void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf, const int max_size,
++	void *cdata, int nmasters, int nslaves, int ntslaves);
++#else
++static inline int msm_bus_rpm_hw_init(struct msm_bus_fabric_registration *pdata,
++	struct msm_bus_hw_algorithm *hw_algo)
++{
++	return 0;
++}
++static inline int msm_bus_remote_hw_commit(struct msm_bus_fabric_registration
++	*fab_pdata, void *hw_data, void **cdata)
++{
++	return 0;
++}
++static inline void msm_bus_rpm_fill_cdata_buffer(int *curr, char *buf,
++	const int max_size, void *cdata, int nmasters, int nslaves,
++	int ntslaves)
++{
++}
++#endif
++
++int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata,
++	struct msm_bus_hw_algorithm *hw_algo);
++int msm_bus_bimc_hw_init(struct msm_bus_fabric_registration *pdata,
++	struct msm_bus_hw_algorithm *hw_algo);
++#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_MSM_BUS_SCALING)
++void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata, int index,
++	uint32_t cl);
++void msm_bus_dbg_commit_data(const char *fabname, void *cdata,
++	int nmasters, int nslaves, int ntslaves, int op);
++#else
++static inline void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata,
++	int index, uint32_t cl)
++{
++}
++static inline void msm_bus_dbg_commit_data(const char *fabname,
++	void *cdata, int nmasters, int nslaves, int ntslaves,
++	int op)
++{
++}
++#endif
++
++#ifdef CONFIG_CORESIGHT
++int msmbus_coresight_init(struct platform_device *pdev);
++void msmbus_coresight_remove(struct platform_device *pdev);
++int msmbus_coresight_init_adhoc(struct platform_device *pdev,
++		struct device_node *of_node);
++void msmbus_coresight_remove_adhoc(struct platform_device *pdev);
++#else
++static inline int msmbus_coresight_init(struct platform_device *pdev)
++{
++	return 0;
++}
++
++static inline void msmbus_coresight_remove(struct platform_device *pdev)
++{
++}
++
++static inline int msmbus_coresight_init_adhoc(struct platform_device *pdev,
++		struct device_node *of_node)
++{
++	return 0;
++}
++
++static inline void msmbus_coresight_remove_adhoc(struct platform_device *pdev)
++{
++}
++#endif
++
++
++#ifdef CONFIG_OF
++void msm_bus_of_get_nfab(struct platform_device *pdev,
++		struct msm_bus_fabric_registration *pdata);
++struct msm_bus_fabric_registration
++	*msm_bus_of_get_fab_data(struct platform_device *pdev);
++#else
++static inline void msm_bus_of_get_nfab(struct platform_device *pdev,
++		struct msm_bus_fabric_registration *pdata)
++{
++	return;
++}
++
++static inline struct msm_bus_fabric_registration
++	*msm_bus_of_get_fab_data(struct platform_device *pdev)
++{
++	return NULL;
++}
++#endif
++
++#endif /*_ARCH_ARM_MACH_MSM_BUS_CORE_H*/
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_dbg.c
+@@ -0,0 +1,810 @@
++/* Copyright (c) 2010-2012, 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include <linux/debugfs.h>
++#include <linux/slab.h>
++#include <linux/mutex.h>
++#include <linux/string.h>
++#include <linux/uaccess.h>
++#include <linux/hrtimer.h>
++#include "msm-bus-board.h"
++#include "msm-bus.h"
++#include "msm_bus_rules.h"
++#include "msm_bus_core.h"
++#include "msm_bus_adhoc.h"
++
++#define CREATE_TRACE_POINTS
++#include <trace/events/trace_msm_bus.h>
++
++#define MAX_BUFF_SIZE 4096
++#define FILL_LIMIT 128
++
++static struct dentry *clients;
++static struct dentry *dir;
++static DEFINE_MUTEX(msm_bus_dbg_fablist_lock);
++struct msm_bus_dbg_state {
++	uint32_t cl;
++	uint8_t enable;
++	uint8_t current_index;
++} clstate;
++
++struct msm_bus_cldata {
++	const struct msm_bus_scale_pdata *pdata;
++	int index;
++	uint32_t clid;
++	int size;
++	struct dentry *file;
++	struct list_head list;
++	char buffer[MAX_BUFF_SIZE];
++};
++
++struct msm_bus_fab_list {
++	const char *name;
++	int size;
++	struct dentry *file;
++	struct list_head list;
++	char buffer[MAX_BUFF_SIZE];
++};
++
++static char *rules_buf;
++
++LIST_HEAD(fabdata_list);
++LIST_HEAD(cl_list);
++
++/**
++ * The following structures and funtions are used for
++ * the test-client which can be created at run-time.
++ */
++
++static struct msm_bus_vectors init_vectors[1];
++static struct msm_bus_vectors current_vectors[1];
++static struct msm_bus_vectors requested_vectors[1];
++
++static struct msm_bus_paths shell_client_usecases[] = {
++	{
++		.num_paths = ARRAY_SIZE(init_vectors),
++		.vectors = init_vectors,
++	},
++	{
++		.num_paths = ARRAY_SIZE(current_vectors),
++		.vectors = current_vectors,
++	},
++	{
++		.num_paths = ARRAY_SIZE(requested_vectors),
++		.vectors = requested_vectors,
++	},
++};
++
++static struct msm_bus_scale_pdata shell_client = {
++	.usecase = shell_client_usecases,
++	.num_usecases = ARRAY_SIZE(shell_client_usecases),
++	.name = "test-client",
++};
++
++static void msm_bus_dbg_init_vectors(void)
++{
++	init_vectors[0].src = -1;
++	init_vectors[0].dst = -1;
++	init_vectors[0].ab = 0;
++	init_vectors[0].ib = 0;
++	current_vectors[0].src = -1;
++	current_vectors[0].dst = -1;
++	current_vectors[0].ab = 0;
++	current_vectors[0].ib = 0;
++	requested_vectors[0].src = -1;
++	requested_vectors[0].dst = -1;
++	requested_vectors[0].ab = 0;
++	requested_vectors[0].ib = 0;
++	clstate.enable = 0;
++	clstate.current_index = 0;
++}
++
++static int msm_bus_dbg_update_cl_request(uint32_t cl)
++{
++	int ret = 0;
++
++	if (clstate.current_index < 2)
++		clstate.current_index = 2;
++	else {
++		clstate.current_index = 1;
++		current_vectors[0].ab = requested_vectors[0].ab;
++		current_vectors[0].ib = requested_vectors[0].ib;
++	}
++
++	if (clstate.enable) {
++		MSM_BUS_DBG("Updating request for shell client, index: %d\n",
++			clstate.current_index);
++		ret = msm_bus_scale_client_update_request(clstate.cl,
++			clstate.current_index);
++	} else
++		MSM_BUS_DBG("Enable bit not set. Skipping update request\n");
++
++	return ret;
++}
++
++static void msm_bus_dbg_unregister_client(uint32_t cl)
++{
++	MSM_BUS_DBG("Unregistering shell client\n");
++	msm_bus_scale_unregister_client(clstate.cl);
++	clstate.cl = 0;
++}
++
++static uint32_t msm_bus_dbg_register_client(void)
++{
++	int ret = 0;
++
++	if (init_vectors[0].src != requested_vectors[0].src) {
++		MSM_BUS_DBG("Shell client master changed. Unregistering\n");
++		msm_bus_dbg_unregister_client(clstate.cl);
++	}
++	if (init_vectors[0].dst != requested_vectors[0].dst) {
++		MSM_BUS_DBG("Shell client slave changed. Unregistering\n");
++		msm_bus_dbg_unregister_client(clstate.cl);
++	}
++
++	current_vectors[0].src = init_vectors[0].src;
++	requested_vectors[0].src = init_vectors[0].src;
++	current_vectors[0].dst = init_vectors[0].dst;
++	requested_vectors[0].dst = init_vectors[0].dst;
++
++	if (!clstate.enable) {
++		MSM_BUS_DBG("Enable bit not set, skipping registration: cl "
++			"%d\n",	clstate.cl);
++		return 0;
++	}
++
++	if (clstate.cl) {
++		MSM_BUS_DBG("Client  registered, skipping registration\n");
++		return clstate.cl;
++	}
++
++	MSM_BUS_DBG("Registering shell client\n");
++	ret = msm_bus_scale_register_client(&shell_client);
++	return ret;
++}
++
++static int msm_bus_dbg_mas_get(void  *data, u64 *val)
++{
++	*val = init_vectors[0].src;
++	MSM_BUS_DBG("Get master: %llu\n", *val);
++	return 0;
++}
++
++static int msm_bus_dbg_mas_set(void  *data, u64 val)
++{
++	init_vectors[0].src = val;
++	MSM_BUS_DBG("Set master: %llu\n", val);
++	clstate.cl = msm_bus_dbg_register_client();
++	return 0;
++}
++DEFINE_SIMPLE_ATTRIBUTE(shell_client_mas_fops, msm_bus_dbg_mas_get,
++	msm_bus_dbg_mas_set, "%llu\n");
++
++static int msm_bus_dbg_slv_get(void  *data, u64 *val)
++{
++	*val = init_vectors[0].dst;
++	MSM_BUS_DBG("Get slave: %llu\n", *val);
++	return 0;
++}
++
++static int msm_bus_dbg_slv_set(void  *data, u64 val)
++{
++	init_vectors[0].dst = val;
++	MSM_BUS_DBG("Set slave: %llu\n", val);
++	clstate.cl = msm_bus_dbg_register_client();
++	return 0;
++}
++DEFINE_SIMPLE_ATTRIBUTE(shell_client_slv_fops, msm_bus_dbg_slv_get,
++	msm_bus_dbg_slv_set, "%llu\n");
++
++static int msm_bus_dbg_ab_get(void  *data, u64 *val)
++{
++	*val = requested_vectors[0].ab;
++	MSM_BUS_DBG("Get ab: %llu\n", *val);
++	return 0;
++}
++
++static int msm_bus_dbg_ab_set(void  *data, u64 val)
++{
++	requested_vectors[0].ab = val;
++	MSM_BUS_DBG("Set ab: %llu\n", val);
++	return 0;
++}
++DEFINE_SIMPLE_ATTRIBUTE(shell_client_ab_fops, msm_bus_dbg_ab_get,
++	msm_bus_dbg_ab_set, "%llu\n");
++
++static int msm_bus_dbg_ib_get(void  *data, u64 *val)
++{
++	*val = requested_vectors[0].ib;
++	MSM_BUS_DBG("Get ib: %llu\n", *val);
++	return 0;
++}
++
++static int msm_bus_dbg_ib_set(void  *data, u64 val)
++{
++	requested_vectors[0].ib = val;
++	MSM_BUS_DBG("Set ib: %llu\n", val);
++	return 0;
++}
++DEFINE_SIMPLE_ATTRIBUTE(shell_client_ib_fops, msm_bus_dbg_ib_get,
++	msm_bus_dbg_ib_set, "%llu\n");
++
++static int msm_bus_dbg_en_get(void  *data, u64 *val)
++{
++	*val = clstate.enable;
++	MSM_BUS_DBG("Get enable: %llu\n", *val);
++	return 0;
++}
++
++static int msm_bus_dbg_en_set(void  *data, u64 val)
++{
++	int ret = 0;
++
++	clstate.enable = val;
++	if (clstate.enable) {
++		if (!clstate.cl) {
++			MSM_BUS_DBG("client: %u\n", clstate.cl);
++			clstate.cl = msm_bus_dbg_register_client();
++			if (clstate.cl)
++				ret = msm_bus_dbg_update_cl_request(clstate.cl);
++		} else {
++			MSM_BUS_DBG("update request for cl: %u\n", clstate.cl);
++			ret = msm_bus_dbg_update_cl_request(clstate.cl);
++		}
++	}
++
++	MSM_BUS_DBG("Set enable: %llu\n", val);
++	return ret;
++}
++DEFINE_SIMPLE_ATTRIBUTE(shell_client_en_fops, msm_bus_dbg_en_get,
++	msm_bus_dbg_en_set, "%llu\n");
++
++/**
++ * The following funtions are used for viewing the client data
++ * and changing the client request at run-time
++ */
++
++static ssize_t client_data_read(struct file *file, char __user *buf,
++	size_t count, loff_t *ppos)
++{
++	int bsize = 0;
++	uint32_t cl = (uint32_t)(uintptr_t)file->private_data;
++	struct msm_bus_cldata *cldata = NULL;
++	int found = 0;
++
++	list_for_each_entry(cldata, &cl_list, list) {
++		if (cldata->clid == cl) {
++			found = 1;
++			break;
++		}
++	}
++	if (!found)
++		return 0;
++
++	bsize = cldata->size;
++	return simple_read_from_buffer(buf, count, ppos,
++		cldata->buffer, bsize);
++}
++
++static int client_data_open(struct inode *inode, struct file *file)
++{
++	file->private_data = inode->i_private;
++	return 0;
++}
++
++static const struct file_operations client_data_fops = {
++	.open		= client_data_open,
++	.read		= client_data_read,
++};
++
++struct dentry *msm_bus_dbg_create(const char *name, mode_t mode,
++	struct dentry *dent, uint32_t clid)
++{
++	if (dent == NULL) {
++		MSM_BUS_DBG("debugfs not ready yet\n");
++		return NULL;
++	}
++	return debugfs_create_file(name, mode, dent, (void *)(uintptr_t)clid,
++		&client_data_fops);
++}
++
++#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_MSM_BUS_SCALING)
++static int msm_bus_dbg_record_client(const struct msm_bus_scale_pdata *pdata,
++	int index, uint32_t clid, struct dentry *file)
++{
++	struct msm_bus_cldata *cldata;
++
++	cldata = kmalloc(sizeof(struct msm_bus_cldata), GFP_KERNEL);
++	if (!cldata) {
++		MSM_BUS_DBG("Failed to allocate memory for client data\n");
++		return -ENOMEM;
++	}
++	cldata->pdata = pdata;
++	cldata->index = index;
++	cldata->clid = clid;
++	cldata->file = file;
++	cldata->size = 0;
++	list_add_tail(&cldata->list, &cl_list);
++	return 0;
++}
++
++static void msm_bus_dbg_free_client(uint32_t clid)
++{
++	struct msm_bus_cldata *cldata = NULL;
++
++	list_for_each_entry(cldata, &cl_list, list) {
++		if (cldata->clid == clid) {
++			debugfs_remove(cldata->file);
++			list_del(&cldata->list);
++			kfree(cldata);
++			break;
++		}
++	}
++}
++
++static int msm_bus_dbg_fill_cl_buffer(const struct msm_bus_scale_pdata *pdata,
++	int index, uint32_t clid)
++{
++	int i = 0, j;
++	char *buf = NULL;
++	struct msm_bus_cldata *cldata = NULL;
++	struct timespec ts;
++	int found = 0;
++
++	list_for_each_entry(cldata, &cl_list, list) {
++		if (cldata->clid == clid) {
++			found = 1;
++			break;
++		}
++	}
++
++	if (!found)
++		return -ENOENT;
++
++	if (cldata->file == NULL) {
++		if (pdata->name == NULL) {
++			MSM_BUS_DBG("Client doesn't have a name\n");
++			return -EINVAL;
++		}
++		cldata->file = msm_bus_dbg_create(pdata->name, S_IRUGO,
++			clients, clid);
++	}
++
++	if (cldata->size < (MAX_BUFF_SIZE - FILL_LIMIT))
++		i = cldata->size;
++	else {
++		i = 0;
++		cldata->size = 0;
++	}
++	buf = cldata->buffer;
++	ts = ktime_to_timespec(ktime_get());
++	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n%d.%d\n",
++		(int)ts.tv_sec, (int)ts.tv_nsec);
++	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "curr   : %d\n", index);
++	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "masters: ");
++
++	for (j = 0; j < pdata->usecase->num_paths; j++)
++		i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%d  ",
++			pdata->usecase[index].vectors[j].src);
++	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nslaves : ");
++	for (j = 0; j < pdata->usecase->num_paths; j++)
++		i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%d  ",
++			pdata->usecase[index].vectors[j].dst);
++	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nab     : ");
++	for (j = 0; j < pdata->usecase->num_paths; j++)
++		i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu  ",
++			pdata->usecase[index].vectors[j].ab);
++	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\nib     : ");
++	for (j = 0; j < pdata->usecase->num_paths; j++)
++		i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "%llu  ",
++			pdata->usecase[index].vectors[j].ib);
++	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
++
++	for (j = 0; j < pdata->usecase->num_paths; j++)
++		trace_bus_update_request((int)ts.tv_sec, (int)ts.tv_nsec,
++		pdata->name, index,
++		pdata->usecase[index].vectors[j].src,
++		pdata->usecase[index].vectors[j].dst,
++		pdata->usecase[index].vectors[j].ab,
++		pdata->usecase[index].vectors[j].ib);
++
++	cldata->size = i;
++	return i;
++}
++#endif
++
++static int msm_bus_dbg_update_request(struct msm_bus_cldata *cldata, int index)
++{
++	int ret = 0;
++
++	if ((index < 0) || (index > cldata->pdata->num_usecases)) {
++		MSM_BUS_DBG("Invalid index!\n");
++		return -EINVAL;
++	}
++	ret = msm_bus_scale_client_update_request(cldata->clid, index);
++	return ret;
++}
++
++static ssize_t  msm_bus_dbg_update_request_write(struct file *file,
++	const char __user *ubuf, size_t cnt, loff_t *ppos)
++{
++	struct msm_bus_cldata *cldata;
++	unsigned long index = 0;
++	int ret = 0;
++	char *chid;
++	char *buf = kmalloc((sizeof(char) * (cnt + 1)), GFP_KERNEL);
++	int found = 0;
++
++	if (!buf || IS_ERR(buf)) {
++		MSM_BUS_ERR("Memory allocation for buffer failed\n");
++		return -ENOMEM;
++	}
++	if (cnt == 0) {
++		kfree(buf);
++		return 0;
++	}
++	if (copy_from_user(buf, ubuf, cnt)) {
++		kfree(buf);
++		return -EFAULT;
++	}
++	buf[cnt] = '\0';
++	chid = buf;
++	MSM_BUS_DBG("buffer: %s\n size: %zu\n", buf, sizeof(ubuf));
++
++	list_for_each_entry(cldata, &cl_list, list) {
++		if (strnstr(chid, cldata->pdata->name, cnt)) {
++			found = 1;
++			cldata = cldata;
++			strsep(&chid, " ");
++			if (chid) {
++				ret = kstrtoul(chid, 10, &index);
++				if (ret) {
++					MSM_BUS_DBG("Index conversion"
++						" failed\n");
++					return -EFAULT;
++				}
++			} else {
++				MSM_BUS_DBG("Error parsing input. Index not"
++					" found\n");
++				found = 0;
++			}
++			break;
++		}
++	}
++
++	if (found)
++		msm_bus_dbg_update_request(cldata, index);
++	kfree(buf);
++	return cnt;
++}
++
++/**
++ * The following funtions are used for viewing the commit data
++ * for each fabric
++ */
++static ssize_t fabric_data_read(struct file *file, char __user *buf,
++	size_t count, loff_t *ppos)
++{
++	struct msm_bus_fab_list *fablist = NULL;
++	int bsize = 0;
++	ssize_t ret;
++	const char *name = file->private_data;
++	int found = 0;
++
++	mutex_lock(&msm_bus_dbg_fablist_lock);
++	list_for_each_entry(fablist, &fabdata_list, list) {
++		if (strcmp(fablist->name, name) == 0) {
++			found = 1;
++			break;
++		}
++	}
++	if (!found)
++		return -ENOENT;
++	bsize = fablist->size;
++	ret = simple_read_from_buffer(buf, count, ppos,
++		fablist->buffer, bsize);
++	mutex_unlock(&msm_bus_dbg_fablist_lock);
++	return ret;
++}
++
++static const struct file_operations fabric_data_fops = {
++	.open		= client_data_open,
++	.read		= fabric_data_read,
++};
++
++static ssize_t rules_dbg_read(struct file *file, char __user *buf,
++	size_t count, loff_t *ppos)
++{
++	ssize_t ret;
++	memset(rules_buf, 0, MAX_BUFF_SIZE);
++	print_rules_buf(rules_buf, MAX_BUFF_SIZE);
++	ret = simple_read_from_buffer(buf, count, ppos,
++		rules_buf, MAX_BUFF_SIZE);
++	return ret;
++}
++
++static int rules_dbg_open(struct inode *inode, struct file *file)
++{
++	file->private_data = inode->i_private;
++	return 0;
++}
++
++static const struct file_operations rules_dbg_fops = {
++	.open		= rules_dbg_open,
++	.read		= rules_dbg_read,
++};
++
++#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_MSM_BUS_SCALING)
++static int msm_bus_dbg_record_fabric(const char *fabname, struct dentry *file)
++{
++	struct msm_bus_fab_list *fablist;
++	int ret = 0;
++
++	mutex_lock(&msm_bus_dbg_fablist_lock);
++	fablist = kmalloc(sizeof(struct msm_bus_fab_list), GFP_KERNEL);
++	if (!fablist) {
++		MSM_BUS_DBG("Failed to allocate memory for commit data\n");
++		ret =  -ENOMEM;
++		goto err;
++	}
++
++	fablist->name = fabname;
++	fablist->size = 0;
++	list_add_tail(&fablist->list, &fabdata_list);
++err:
++	mutex_unlock(&msm_bus_dbg_fablist_lock);
++	return ret;
++}
++
++static void msm_bus_dbg_free_fabric(const char *fabname)
++{
++	struct msm_bus_fab_list *fablist = NULL;
++
++	mutex_lock(&msm_bus_dbg_fablist_lock);
++	list_for_each_entry(fablist, &fabdata_list, list) {
++		if (strcmp(fablist->name, fabname) == 0) {
++			debugfs_remove(fablist->file);
++			list_del(&fablist->list);
++			kfree(fablist);
++			break;
++		}
++	}
++	mutex_unlock(&msm_bus_dbg_fablist_lock);
++}
++
++static int msm_bus_dbg_fill_fab_buffer(const char *fabname,
++	void *cdata, int nmasters, int nslaves,
++	int ntslaves)
++{
++	int i;
++	char *buf = NULL;
++	struct msm_bus_fab_list *fablist = NULL;
++	struct timespec ts;
++	int found = 0;
++
++	mutex_lock(&msm_bus_dbg_fablist_lock);
++	list_for_each_entry(fablist, &fabdata_list, list) {
++		if (strcmp(fablist->name, fabname) == 0) {
++			found = 1;
++			break;
++		}
++	}
++	if (!found)
++		return -ENOENT;
++
++	if (fablist->file == NULL) {
++		MSM_BUS_DBG("Fabric dbg entry does not exist\n");
++		mutex_unlock(&msm_bus_dbg_fablist_lock);
++		return -EFAULT;
++	}
++
++	if (fablist->size < MAX_BUFF_SIZE - 256)
++		i = fablist->size;
++	else {
++		i = 0;
++		fablist->size = 0;
++	}
++	buf = fablist->buffer;
++	mutex_unlock(&msm_bus_dbg_fablist_lock);
++	ts = ktime_to_timespec(ktime_get());
++	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n%d.%d\n",
++		(int)ts.tv_sec, (int)ts.tv_nsec);
++
++	msm_bus_rpm_fill_cdata_buffer(&i, buf, MAX_BUFF_SIZE, cdata,
++		nmasters, nslaves, ntslaves);
++	i += scnprintf(buf + i, MAX_BUFF_SIZE - i, "\n");
++	mutex_lock(&msm_bus_dbg_fablist_lock);
++	fablist->size = i;
++	mutex_unlock(&msm_bus_dbg_fablist_lock);
++	return 0;
++}
++#endif
++
++static const struct file_operations msm_bus_dbg_update_request_fops = {
++	.open = client_data_open,
++	.write = msm_bus_dbg_update_request_write,
++};
++
++#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_MSM_BUS_SCALING)
++/**
++ * msm_bus_dbg_client_data() - Add debug data for clients
++ * @pdata: Platform data of the client
++ * @index: The current index or operation to be performed
++ * @clid: Client handle obtained during registration
++ */
++void msm_bus_dbg_client_data(struct msm_bus_scale_pdata *pdata, int index,
++	uint32_t clid)
++{
++	struct dentry *file = NULL;
++
++	if (index == MSM_BUS_DBG_REGISTER) {
++		msm_bus_dbg_record_client(pdata, index, clid, file);
++		if (!pdata->name) {
++			MSM_BUS_DBG("Cannot create debugfs entry. Null name\n");
++			return;
++		}
++	} else if (index == MSM_BUS_DBG_UNREGISTER) {
++		msm_bus_dbg_free_client(clid);
++		MSM_BUS_DBG("Client %d unregistered\n", clid);
++	} else
++		msm_bus_dbg_fill_cl_buffer(pdata, index, clid);
++}
++EXPORT_SYMBOL(msm_bus_dbg_client_data);
++
++/**
++ * msm_bus_dbg_commit_data() - Add commit data from fabrics
++ * @fabname: Fabric name specified in platform data
++ * @cdata: Commit Data
++ * @nmasters: Number of masters attached to fabric
++ * @nslaves: Number of slaves attached to fabric
++ * @ntslaves: Number of tiered slaves attached to fabric
++ * @op: Operation to be performed
++ */
++void msm_bus_dbg_commit_data(const char *fabname, void *cdata,
++	int nmasters, int nslaves, int ntslaves, int op)
++{
++	struct dentry *file = NULL;
++
++	if (op == MSM_BUS_DBG_REGISTER)
++		msm_bus_dbg_record_fabric(fabname, file);
++	else if (op == MSM_BUS_DBG_UNREGISTER)
++		msm_bus_dbg_free_fabric(fabname);
++	else
++		msm_bus_dbg_fill_fab_buffer(fabname, cdata, nmasters,
++			nslaves, ntslaves);
++}
++EXPORT_SYMBOL(msm_bus_dbg_commit_data);
++#endif
++
++static int __init msm_bus_debugfs_init(void)
++{
++	struct dentry *commit, *shell_client, *rules_dbg;
++	struct msm_bus_fab_list *fablist;
++	struct msm_bus_cldata *cldata = NULL;
++	uint64_t val = 0;
++
++	dir = debugfs_create_dir("msm-bus-dbg", NULL);
++	if ((!dir) || IS_ERR(dir)) {
++		MSM_BUS_ERR("Couldn't create msm-bus-dbg\n");
++		goto err;
++	}
++
++	clients = debugfs_create_dir("client-data", dir);
++	if ((!dir) || IS_ERR(dir)) {
++		MSM_BUS_ERR("Couldn't create clients\n");
++		goto err;
++	}
++
++	shell_client = debugfs_create_dir("shell-client", dir);
++	if ((!dir) || IS_ERR(dir)) {
++		MSM_BUS_ERR("Couldn't create clients\n");
++		goto err;
++	}
++
++	commit = debugfs_create_dir("commit-data", dir);
++	if ((!dir) || IS_ERR(dir)) {
++		MSM_BUS_ERR("Couldn't create commit\n");
++		goto err;
++	}
++
++	rules_dbg = debugfs_create_dir("rules-dbg", dir);
++	if ((!rules_dbg) || IS_ERR(rules_dbg)) {
++		MSM_BUS_ERR("Couldn't create rules-dbg\n");
++		goto err;
++	}
++
++	if (debugfs_create_file("print_rules", S_IRUGO | S_IWUSR,
++		rules_dbg, &val, &rules_dbg_fops) == NULL)
++		goto err;
++
++	if (debugfs_create_file("update_request", S_IRUGO | S_IWUSR,
++		shell_client, &val, &shell_client_en_fops) == NULL)
++		goto err;
++	if (debugfs_create_file("ib", S_IRUGO | S_IWUSR, shell_client, &val,
++		&shell_client_ib_fops) == NULL)
++		goto err;
++	if (debugfs_create_file("ab", S_IRUGO | S_IWUSR, shell_client, &val,
++		&shell_client_ab_fops) == NULL)
++		goto err;
++	if (debugfs_create_file("slv", S_IRUGO | S_IWUSR, shell_client,
++		&val, &shell_client_slv_fops) == NULL)
++		goto err;
++	if (debugfs_create_file("mas", S_IRUGO | S_IWUSR, shell_client,
++		&val, &shell_client_mas_fops) == NULL)
++		goto err;
++	if (debugfs_create_file("update-request", S_IRUGO | S_IWUSR,
++		clients, NULL, &msm_bus_dbg_update_request_fops) == NULL)
++		goto err;
++
++	rules_buf = kzalloc(MAX_BUFF_SIZE, GFP_KERNEL);
++	if (!rules_buf) {
++		MSM_BUS_ERR("Failed to alloc rules_buf");
++		goto err;
++	}
++
++	list_for_each_entry(cldata, &cl_list, list) {
++		if (cldata->pdata->name == NULL) {
++			MSM_BUS_DBG("Client name not found\n");
++			continue;
++		}
++		cldata->file = msm_bus_dbg_create(cldata->
++			pdata->name, S_IRUGO, clients, cldata->clid);
++	}
++
++	mutex_lock(&msm_bus_dbg_fablist_lock);
++	list_for_each_entry(fablist, &fabdata_list, list) {
++		fablist->file = debugfs_create_file(fablist->name, S_IRUGO,
++			commit, (void *)fablist->name, &fabric_data_fops);
++		if (fablist->file == NULL) {
++			MSM_BUS_DBG("Cannot create files for commit data\n");
++			kfree(rules_buf);
++			goto err;
++		}
++	}
++	mutex_unlock(&msm_bus_dbg_fablist_lock);
++
++	msm_bus_dbg_init_vectors();
++	return 0;
++err:
++	debugfs_remove_recursive(dir);
++	return -ENODEV;
++}
++late_initcall(msm_bus_debugfs_init);
++
++static void __exit msm_bus_dbg_teardown(void)
++{
++	struct msm_bus_fab_list *fablist = NULL, *fablist_temp;
++	struct msm_bus_cldata *cldata = NULL, *cldata_temp;
++
++	debugfs_remove_recursive(dir);
++	list_for_each_entry_safe(cldata, cldata_temp, &cl_list, list) {
++		list_del(&cldata->list);
++		kfree(cldata);
++	}
++	mutex_lock(&msm_bus_dbg_fablist_lock);
++	list_for_each_entry_safe(fablist, fablist_temp, &fabdata_list, list) {
++		list_del(&fablist->list);
++		kfree(fablist);
++	}
++	kfree(rules_buf);
++	mutex_unlock(&msm_bus_dbg_fablist_lock);
++}
++module_exit(msm_bus_dbg_teardown);
++MODULE_DESCRIPTION("Debugfs for msm bus scaling client");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Gagan Mac <gmac@codeaurora.org>");
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_fabric_adhoc.c
+@@ -0,0 +1,1281 @@
++/* Copyright (c) 2014, Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/device.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include "rpm-smd.h"
++#include "msm_bus_core.h"
++#include "msm_bus_adhoc.h"
++#include "msm_bus_noc.h"
++#include "msm_bus_bimc.h"
++
++ssize_t vrail_show(struct device *dev, struct device_attribute *attr,
++			  char *buf)
++{
++	struct msm_bus_node_info_type *node_info = NULL;
++	struct msm_bus_node_device_type *bus_node = NULL;
++
++	bus_node = dev->platform_data;
++	if (!bus_node)
++		return -EINVAL;
++	node_info = bus_node->node_info;
++
++	return snprintf(buf, PAGE_SIZE, "%u", node_info->vrail_comp);
++}
++
++ssize_t vrail_store(struct device *dev, struct device_attribute *attr,
++			   const char *buf, size_t count)
++{
++	struct msm_bus_node_info_type *node_info = NULL;
++	struct msm_bus_node_device_type *bus_node = NULL;
++	int ret = 0;
++
++	bus_node = dev->platform_data;
++	if (!bus_node)
++		return -EINVAL;
++	node_info = bus_node->node_info;
++
++	ret = sscanf(buf, "%u", &node_info->vrail_comp);
++	if (ret != 1)
++		return -EINVAL;
++	return count;
++}
++
++DEVICE_ATTR(vrail, 0600, vrail_show, vrail_store);
++
++struct static_rules_type {
++	int num_rules;
++	struct bus_rule_type *rules;
++};
++
++static struct static_rules_type static_rules;
++
++static int enable_nodeclk(struct nodeclk *nclk)
++{
++	int ret = 0;
++
++	if (!nclk->enable) {
++		ret = clk_prepare_enable(nclk->clk);
++
++		if (ret) {
++			MSM_BUS_ERR("%s: failed to enable clk ", __func__);
++			nclk->enable = false;
++		} else
++			nclk->enable = true;
++	}
++	return ret;
++}
++
++static int disable_nodeclk(struct nodeclk *nclk)
++{
++	int ret = 0;
++
++	if (nclk->enable) {
++		clk_disable_unprepare(nclk->clk);
++		nclk->enable = false;
++	}
++	return ret;
++}
++
++static int setrate_nodeclk(struct nodeclk *nclk, long rate)
++{
++	int ret = 0;
++
++	ret = clk_set_rate(nclk->clk, rate);
++
++	if (ret)
++		MSM_BUS_ERR("%s: failed to setrate clk", __func__);
++	return ret;
++}
++
++static int msm_bus_agg_fab_clks(struct device *bus_dev, void *data)
++{
++	struct msm_bus_node_device_type *node = NULL;
++	int ret = 0;
++	int ctx = *(int *)data;
++
++	if (ctx >= NUM_CTX) {
++		MSM_BUS_ERR("%s: Invalid Context %d", __func__, ctx);
++		goto exit_agg_fab_clks;
++	}
++
++	node = bus_dev->platform_data;
++	if (!node) {
++		MSM_BUS_ERR("%s: Can't get device info", __func__);
++		goto exit_agg_fab_clks;
++	}
++
++	if (!node->node_info->is_fab_dev) {
++		struct msm_bus_node_device_type *bus_dev = NULL;
++
++		bus_dev = node->node_info->bus_device->platform_data;
++
++		if (node->cur_clk_hz[ctx] >= bus_dev->cur_clk_hz[ctx])
++			bus_dev->cur_clk_hz[ctx] = node->cur_clk_hz[ctx];
++	}
++
++exit_agg_fab_clks:
++	return ret;
++}
++
++static int msm_bus_reset_fab_clks(struct device *bus_dev, void *data)
++{
++	struct msm_bus_node_device_type *node = NULL;
++	int ret = 0;
++	int ctx = *(int *)data;
++
++	if (ctx >= NUM_CTX) {
++		MSM_BUS_ERR("%s: Invalid Context %d", __func__, ctx);
++		goto exit_reset_fab_clks;
++	}
++
++	node = bus_dev->platform_data;
++	if (!node) {
++		MSM_BUS_ERR("%s: Can't get device info", __func__);
++		goto exit_reset_fab_clks;
++	}
++
++	if (node->node_info->is_fab_dev) {
++		node->cur_clk_hz[ctx] = 0;
++		MSM_BUS_DBG("Resetting for node %d", node->node_info->id);
++	}
++exit_reset_fab_clks:
++	return ret;
++}
++
++
++static int send_rpm_msg(struct device *device)
++{
++	int ret = 0;
++	int ctx;
++	int rsc_type;
++	struct msm_bus_node_device_type *ndev =
++					device->platform_data;
++	struct msm_rpm_kvp rpm_kvp;
++
++	if (!ndev) {
++		MSM_BUS_ERR("%s: Error getting node info.", __func__);
++		ret = -ENODEV;
++		goto exit_send_rpm_msg;
++	}
++
++	rpm_kvp.length = sizeof(uint64_t);
++	rpm_kvp.key = RPM_MASTER_FIELD_BW;
++
++	for (ctx = MSM_RPM_CTX_ACTIVE_SET; ctx <= MSM_RPM_CTX_SLEEP_SET;
++					ctx++) {
++		if (ctx == MSM_RPM_CTX_ACTIVE_SET)
++			rpm_kvp.data =
++			(uint8_t *)&ndev->node_ab.ab[MSM_RPM_CTX_ACTIVE_SET];
++		else {
++			rpm_kvp.data =
++			(uint8_t *) &ndev->node_ab.ab[MSM_RPM_CTX_SLEEP_SET];
++		}
++
++		if (ndev->node_info->mas_rpm_id != -1) {
++			rsc_type = RPM_BUS_MASTER_REQ;
++			ret = msm_rpm_send_message(ctx, rsc_type,
++				ndev->node_info->mas_rpm_id, &rpm_kvp, 1);
++			if (ret) {
++				MSM_BUS_ERR("%s: Failed to send RPM message:",
++						__func__);
++				MSM_BUS_ERR("%s:Node Id %d RPM id %d",
++				__func__, ndev->node_info->id,
++					 ndev->node_info->mas_rpm_id);
++				goto exit_send_rpm_msg;
++			}
++		}
++
++		if (ndev->node_info->slv_rpm_id != -1) {
++			rsc_type = RPM_BUS_SLAVE_REQ;
++			ret = msm_rpm_send_message(ctx, rsc_type,
++				ndev->node_info->slv_rpm_id, &rpm_kvp, 1);
++			if (ret) {
++				MSM_BUS_ERR("%s: Failed to send RPM message:",
++							__func__);
++				MSM_BUS_ERR("%s: Node Id %d RPM id %d",
++				__func__, ndev->node_info->id,
++					ndev->node_info->slv_rpm_id);
++				goto exit_send_rpm_msg;
++			}
++		}
++	}
++exit_send_rpm_msg:
++	return ret;
++}
++
++static int flush_bw_data(struct device *node_device, int ctx)
++{
++	struct msm_bus_node_device_type *node_info;
++	int ret = 0;
++
++	node_info = node_device->platform_data;
++	if (!node_info) {
++		MSM_BUS_ERR("%s: Unable to find bus device for device",
++			__func__);
++		ret = -ENODEV;
++		goto exit_flush_bw_data;
++	}
++
++	if (node_info->node_ab.dirty) {
++		if (node_info->ap_owned) {
++			struct msm_bus_node_device_type *bus_device =
++				node_info->node_info->bus_device->platform_data;
++			struct msm_bus_fab_device_type *fabdev =
++							bus_device->fabdev;
++
++			if (fabdev && fabdev->noc_ops.update_bw_reg &&
++				fabdev->noc_ops.update_bw_reg
++					(node_info->node_info->qos_params.mode))
++				ret = fabdev->noc_ops.set_bw(node_info,
++							fabdev->qos_base,
++							fabdev->base_offset,
++							fabdev->qos_off,
++							fabdev->qos_freq);
++		} else {
++			ret = send_rpm_msg(node_device);
++
++			if (ret)
++				MSM_BUS_ERR("%s: Failed to send RPM msg for%d",
++				__func__, node_info->node_info->id);
++		}
++		node_info->node_ab.dirty = false;
++	}
++
++exit_flush_bw_data:
++	return ret;
++
++}
++
++static int flush_clk_data(struct device *node_device, int ctx)
++{
++	struct msm_bus_node_device_type *node;
++	struct nodeclk *nodeclk = NULL;
++	int ret = 0;
++
++	node = node_device->platform_data;
++	if (!node) {
++		MSM_BUS_ERR("Unable to find bus device");
++		ret = -ENODEV;
++		goto exit_flush_clk_data;
++	}
++
++	nodeclk = &node->clk[ctx];
++	if (node->node_info->is_fab_dev) {
++		if (nodeclk->rate != node->cur_clk_hz[ctx]) {
++			nodeclk->rate = node->cur_clk_hz[ctx];
++			nodeclk->dirty = true;
++		}
++	}
++
++	if (nodeclk && nodeclk->clk && nodeclk->dirty) {
++		long rounded_rate;
++
++		if (nodeclk->rate) {
++			rounded_rate = clk_round_rate(nodeclk->clk,
++							nodeclk->rate);
++			ret = setrate_nodeclk(nodeclk, rounded_rate);
++
++			if (ret) {
++				MSM_BUS_ERR("%s: Failed to set_rate %lu for %d",
++					__func__, rounded_rate,
++						node->node_info->id);
++				ret = -ENODEV;
++				goto exit_flush_clk_data;
++			}
++
++			ret = enable_nodeclk(nodeclk);
++		} else
++			ret = disable_nodeclk(nodeclk);
++
++		if (ret) {
++			MSM_BUS_ERR("%s: Failed to enable for %d", __func__,
++						node->node_info->id);
++			ret = -ENODEV;
++			goto exit_flush_clk_data;
++		}
++		MSM_BUS_DBG("%s: Updated %d clk to %llu", __func__,
++				node->node_info->id, nodeclk->rate);
++
++	}
++exit_flush_clk_data:
++	/* Reset the aggregated clock rate for fab devices*/
++	if (node && node->node_info->is_fab_dev)
++		node->cur_clk_hz[ctx] = 0;
++
++	if (nodeclk)
++		nodeclk->dirty = 0;
++	return ret;
++}
++
++int msm_bus_commit_data(int *dirty_nodes, int ctx, int num_dirty)
++{
++	int ret = 0;
++	int i = 0;
++
++	/* Aggregate the bus clocks */
++	bus_for_each_dev(&msm_bus_type, NULL, (void *)&ctx,
++				msm_bus_agg_fab_clks);
++
++	for (i = 0; i < num_dirty; i++) {
++		struct device *node_device =
++					bus_find_device(&msm_bus_type, NULL,
++						(void *)&dirty_nodes[i],
++						msm_bus_device_match_adhoc);
++
++		if (!node_device) {
++			MSM_BUS_ERR("Can't find device for %d", dirty_nodes[i]);
++			continue;
++		}
++
++		ret = flush_bw_data(node_device, ctx);
++		if (ret)
++			MSM_BUS_ERR("%s: Error flushing bw data for node %d",
++					__func__, dirty_nodes[i]);
++
++		ret = flush_clk_data(node_device, ctx);
++		if (ret)
++			MSM_BUS_ERR("%s: Error flushing clk data for node %d",
++					__func__, dirty_nodes[i]);
++	}
++	kfree(dirty_nodes);
++	/* Aggregate the bus clocks */
++	bus_for_each_dev(&msm_bus_type, NULL, (void *)&ctx,
++				msm_bus_reset_fab_clks);
++	return ret;
++}
++
++void *msm_bus_realloc_devmem(struct device *dev, void *p, size_t old_size,
++					size_t new_size, gfp_t flags)
++{
++	void *ret;
++	size_t copy_size = old_size;
++
++	if (!new_size) {
++		devm_kfree(dev, p);
++		return ZERO_SIZE_PTR;
++	}
++
++	if (new_size < old_size)
++		copy_size = new_size;
++
++	ret = devm_kzalloc(dev, new_size, flags);
++	if (!ret) {
++		MSM_BUS_ERR("%s: Error Reallocating memory", __func__);
++		goto exit_realloc_devmem;
++	}
++
++	memcpy(ret, p, copy_size);
++	devm_kfree(dev, p);
++exit_realloc_devmem:
++	return ret;
++}
++
++
++static int add_dirty_node(int **dirty_nodes, int id, int *num_dirty)
++{
++	int i;
++	int found = 0;
++	int ret = 0;
++	int *dnode = NULL;
++
++	for (i = 0; i < *num_dirty; i++) {
++		if ((*dirty_nodes)[i] == id) {
++			found = 1;
++			break;
++		}
++	}
++
++	if (!found) {
++		(*num_dirty)++;
++		dnode =
++			krealloc(*dirty_nodes, sizeof(int) * (*num_dirty),
++								GFP_KERNEL);
++
++		if (ZERO_OR_NULL_PTR(dnode)) {
++			MSM_BUS_ERR("%s: Failure allocating dirty nodes array",
++								 __func__);
++			ret = -ENOMEM;
++		} else {
++			*dirty_nodes = dnode;
++			(*dirty_nodes)[(*num_dirty) - 1] = id;
++		}
++	}
++
++	return ret;
++}
++
++int msm_bus_update_bw(struct msm_bus_node_device_type *nodedev, int ctx,
++			int64_t add_bw, int **dirty_nodes, int *num_dirty)
++{
++	int ret = 0;
++	int i, j;
++	uint64_t cur_ab_slp = 0;
++	uint64_t cur_ab_act = 0;
++
++	if (nodedev->node_info->virt_dev)
++		goto exit_update_bw;
++
++	for (i = 0; i < NUM_CTX; i++) {
++		for (j = 0; j < nodedev->num_lnodes; j++) {
++			if (i == DUAL_CTX) {
++				cur_ab_act +=
++					nodedev->lnode_list[j].lnode_ab[i];
++				cur_ab_slp +=
++					nodedev->lnode_list[j].lnode_ab[i];
++			} else
++				cur_ab_act +=
++					nodedev->lnode_list[j].lnode_ab[i];
++		}
++	}
++
++	if (nodedev->node_ab.ab[MSM_RPM_CTX_ACTIVE_SET] != cur_ab_act) {
++		nodedev->node_ab.ab[MSM_RPM_CTX_ACTIVE_SET] = cur_ab_act;
++		nodedev->node_ab.ab[MSM_RPM_CTX_SLEEP_SET] = cur_ab_slp;
++		nodedev->node_ab.dirty = true;
++		ret = add_dirty_node(dirty_nodes, nodedev->node_info->id,
++								num_dirty);
++
++		if (ret) {
++			MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__,
++						nodedev->node_info->id);
++			goto exit_update_bw;
++		}
++	}
++
++exit_update_bw:
++	return ret;
++}
++
++int msm_bus_update_clks(struct msm_bus_node_device_type *nodedev,
++		int ctx, int **dirty_nodes, int *num_dirty)
++{
++	int status = 0;
++	struct nodeclk *nodeclk;
++	struct nodeclk *busclk;
++	struct msm_bus_node_device_type *bus_info = NULL;
++	uint64_t req_clk;
++
++	bus_info = nodedev->node_info->bus_device->platform_data;
++
++	if (!bus_info) {
++		MSM_BUS_ERR("%s: Unable to find bus device for device %d",
++			__func__, nodedev->node_info->id);
++		status = -ENODEV;
++		goto exit_set_clks;
++	}
++
++	req_clk = nodedev->cur_clk_hz[ctx];
++	busclk = &bus_info->clk[ctx];
++
++	if (busclk->rate != req_clk) {
++		busclk->rate = req_clk;
++		busclk->dirty = 1;
++		MSM_BUS_DBG("%s: Modifying bus clk %d Rate %llu", __func__,
++					bus_info->node_info->id, req_clk);
++		status = add_dirty_node(dirty_nodes, bus_info->node_info->id,
++								num_dirty);
++
++		if (status) {
++			MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__,
++						bus_info->node_info->id);
++			goto exit_set_clks;
++		}
++	}
++
++	req_clk = nodedev->cur_clk_hz[ctx];
++	nodeclk = &nodedev->clk[ctx];
++
++	if (IS_ERR_OR_NULL(nodeclk))
++		goto exit_set_clks;
++
++	if (!nodeclk->dirty || (nodeclk->dirty && (nodeclk->rate < req_clk))) {
++		nodeclk->rate = req_clk;
++		nodeclk->dirty = 1;
++		MSM_BUS_DBG("%s: Modifying node clk %d Rate %llu", __func__,
++					nodedev->node_info->id, req_clk);
++		status = add_dirty_node(dirty_nodes, nodedev->node_info->id,
++								num_dirty);
++		if (status) {
++			MSM_BUS_ERR("%s: Failed to add dirty node %d", __func__,
++						nodedev->node_info->id);
++			goto exit_set_clks;
++		}
++	}
++
++exit_set_clks:
++	return status;
++}
++
++static void msm_bus_fab_init_noc_ops(struct msm_bus_node_device_type *bus_dev)
++{
++	switch (bus_dev->fabdev->bus_type) {
++	case MSM_BUS_NOC:
++		msm_bus_noc_set_ops(bus_dev);
++		break;
++	case MSM_BUS_BIMC:
++		msm_bus_bimc_set_ops(bus_dev);
++		break;
++	default:
++		MSM_BUS_ERR("%s: Invalid Bus type", __func__);
++	}
++}
++
++static int msm_bus_qos_disable_clk(struct msm_bus_node_device_type *node,
++				int disable_bus_qos_clk)
++{
++	struct msm_bus_node_device_type *bus_node = NULL;
++	int ret = 0;
++
++	if (!node) {
++		ret = -ENXIO;
++		goto exit_disable_qos_clk;
++	}
++
++	bus_node = node->node_info->bus_device->platform_data;
++
++	if (!bus_node) {
++		ret = -ENXIO;
++		goto exit_disable_qos_clk;
++	}
++
++	if (disable_bus_qos_clk)
++		ret = disable_nodeclk(&bus_node->clk[DUAL_CTX]);
++
++	if (ret) {
++		MSM_BUS_ERR("%s: Failed to disable bus clk, node %d",
++			__func__, node->node_info->id);
++		goto exit_disable_qos_clk;
++	}
++
++	if (!IS_ERR_OR_NULL(node->qos_clk.clk)) {
++		ret = disable_nodeclk(&node->qos_clk);
++
++		if (ret) {
++			MSM_BUS_ERR("%s: Failed to disable mas qos clk,node %d",
++				__func__, node->node_info->id);
++			goto exit_disable_qos_clk;
++		}
++	}
++
++exit_disable_qos_clk:
++	return ret;
++}
++
++static int msm_bus_qos_enable_clk(struct msm_bus_node_device_type *node)
++{
++	struct msm_bus_node_device_type *bus_node = NULL;
++	long rounded_rate;
++	int ret = 0;
++	int bus_qos_enabled = 0;
++
++	if (!node) {
++		ret = -ENXIO;
++		goto exit_enable_qos_clk;
++	}
++
++	bus_node = node->node_info->bus_device->platform_data;
++
++	if (!bus_node) {
++		ret = -ENXIO;
++		goto exit_enable_qos_clk;
++	}
++
++	/* Check if the bus clk is already set before trying to set it
++	 * Do this only during
++	 *	a. Bootup
++	 *	b. Only for bus clks
++	 **/
++	if (!clk_get_rate(bus_node->clk[DUAL_CTX].clk)) {
++		rounded_rate = clk_round_rate(bus_node->clk[DUAL_CTX].clk, 1);
++		ret = setrate_nodeclk(&bus_node->clk[DUAL_CTX], rounded_rate);
++		if (ret) {
++			MSM_BUS_ERR("%s: Failed to set bus clk, node %d",
++				__func__, node->node_info->id);
++			goto exit_enable_qos_clk;
++		}
++
++		ret = enable_nodeclk(&bus_node->clk[DUAL_CTX]);
++		if (ret) {
++			MSM_BUS_ERR("%s: Failed to enable bus clk, node %d",
++				__func__, node->node_info->id);
++			goto exit_enable_qos_clk;
++		}
++		bus_qos_enabled = 1;
++	}
++
++	if (!IS_ERR_OR_NULL(node->qos_clk.clk)) {
++		rounded_rate = clk_round_rate(node->qos_clk.clk, 1);
++		ret = setrate_nodeclk(&node->qos_clk, rounded_rate);
++		if (ret) {
++			MSM_BUS_ERR("%s: Failed to enable mas qos clk, node %d",
++				__func__, node->node_info->id);
++			goto exit_enable_qos_clk;
++		}
++
++		ret = enable_nodeclk(&node->qos_clk);
++		if (ret) {
++			MSM_BUS_ERR("Err enable mas qos clk, node %d ret %d",
++				node->node_info->id, ret);
++			goto exit_enable_qos_clk;
++		}
++	}
++	ret = bus_qos_enabled;
++
++exit_enable_qos_clk:
++	return ret;
++}
++
++int msm_bus_enable_limiter(struct msm_bus_node_device_type *node_dev,
++				bool enable, uint64_t lim_bw)
++{
++	int ret = 0;
++	struct msm_bus_node_device_type *bus_node_dev;
++
++	if (!node_dev) {
++		MSM_BUS_ERR("No device specified");
++		ret = -ENXIO;
++		goto exit_enable_limiter;
++	}
++
++	if (!node_dev->ap_owned) {
++		MSM_BUS_ERR("Device is not AP owned %d.",
++						node_dev->node_info->id);
++		ret = -ENXIO;
++		goto exit_enable_limiter;
++	}
++
++	bus_node_dev = node_dev->node_info->bus_device->platform_data;
++	if (!bus_node_dev) {
++		MSM_BUS_ERR("Unable to get bus device infofor %d",
++			node_dev->node_info->id);
++		ret = -ENXIO;
++		goto exit_enable_limiter;
++	}
++	if (bus_node_dev->fabdev &&
++		bus_node_dev->fabdev->noc_ops.limit_mport) {
++		ret = msm_bus_qos_enable_clk(node_dev);
++		if (ret < 0) {
++			MSM_BUS_ERR("Can't Enable QoS clk %d",
++				node_dev->node_info->id);
++			goto exit_enable_limiter;
++		}
++		bus_node_dev->fabdev->noc_ops.limit_mport(
++				node_dev,
++				bus_node_dev->fabdev->qos_base,
++				bus_node_dev->fabdev->base_offset,
++				bus_node_dev->fabdev->qos_off,
++				bus_node_dev->fabdev->qos_freq,
++				enable, lim_bw);
++		msm_bus_qos_disable_clk(node_dev, ret);
++	}
++
++exit_enable_limiter:
++	return ret;
++}
++
++static int msm_bus_dev_init_qos(struct device *dev, void *data)
++{
++	int ret = 0;
++	struct msm_bus_node_device_type *node_dev = NULL;
++
++	node_dev = dev->platform_data;
++
++	if (!node_dev) {
++		MSM_BUS_ERR("%s: Unable to get node device info" , __func__);
++		ret = -ENXIO;
++		goto exit_init_qos;
++	}
++
++	MSM_BUS_DBG("Device = %d", node_dev->node_info->id);
++
++	if (node_dev->ap_owned) {
++		struct msm_bus_node_device_type *bus_node_info;
++
++		bus_node_info = node_dev->node_info->bus_device->platform_data;
++
++		if (!bus_node_info) {
++			MSM_BUS_ERR("%s: Unable to get bus device infofor %d",
++				__func__,
++				node_dev->node_info->id);
++			ret = -ENXIO;
++			goto exit_init_qos;
++		}
++
++		if (bus_node_info->fabdev &&
++			bus_node_info->fabdev->noc_ops.qos_init) {
++			int ret = 0;
++
++			if (node_dev->ap_owned &&
++				(node_dev->node_info->qos_params.mode) != -1) {
++
++				if (bus_node_info->fabdev->bypass_qos_prg)
++					goto exit_init_qos;
++
++				ret = msm_bus_qos_enable_clk(node_dev);
++				if (ret < 0) {
++					MSM_BUS_ERR("Can't Enable QoS clk %d",
++					node_dev->node_info->id);
++					goto exit_init_qos;
++				}
++
++				bus_node_info->fabdev->noc_ops.qos_init(
++					node_dev,
++					bus_node_info->fabdev->qos_base,
++					bus_node_info->fabdev->base_offset,
++					bus_node_info->fabdev->qos_off,
++					bus_node_info->fabdev->qos_freq);
++				msm_bus_qos_disable_clk(node_dev, ret);
++			}
++		} else
++			MSM_BUS_ERR("%s: Skipping QOS init for %d",
++				__func__, node_dev->node_info->id);
++	}
++exit_init_qos:
++	return ret;
++}
++
++static int msm_bus_fabric_init(struct device *dev,
++			struct msm_bus_node_device_type *pdata)
++{
++	struct msm_bus_fab_device_type *fabdev;
++	struct msm_bus_node_device_type *node_dev = NULL;
++	int ret = 0;
++
++	node_dev = dev->platform_data;
++	if (!node_dev) {
++		MSM_BUS_ERR("%s: Unable to get bus device info" , __func__);
++		ret = -ENXIO;
++		goto exit_fabric_init;
++	}
++
++	if (node_dev->node_info->virt_dev) {
++		MSM_BUS_ERR("%s: Skip Fab init for virtual device %d", __func__,
++						node_dev->node_info->id);
++		goto exit_fabric_init;
++	}
++
++	fabdev = devm_kzalloc(dev, sizeof(struct msm_bus_fab_device_type),
++								GFP_KERNEL);
++	if (!fabdev) {
++		MSM_BUS_ERR("Fabric alloc failed\n");
++		ret = -ENOMEM;
++		goto exit_fabric_init;
++	}
++
++	node_dev->fabdev = fabdev;
++	fabdev->pqos_base = pdata->fabdev->pqos_base;
++	fabdev->qos_range = pdata->fabdev->qos_range;
++	fabdev->base_offset = pdata->fabdev->base_offset;
++	fabdev->qos_off = pdata->fabdev->qos_off;
++	fabdev->qos_freq = pdata->fabdev->qos_freq;
++	fabdev->bus_type = pdata->fabdev->bus_type;
++	fabdev->bypass_qos_prg = pdata->fabdev->bypass_qos_prg;
++	fabdev->util_fact = pdata->fabdev->util_fact;
++	fabdev->vrail_comp = pdata->fabdev->vrail_comp;
++	msm_bus_fab_init_noc_ops(node_dev);
++
++	fabdev->qos_base = devm_ioremap(dev,
++				fabdev->pqos_base, fabdev->qos_range);
++	if (!fabdev->qos_base) {
++		MSM_BUS_ERR("%s: Error remapping address 0x%zx :bus device %d",
++			__func__,
++			 (size_t)fabdev->pqos_base, node_dev->node_info->id);
++		ret = -ENOMEM;
++		goto exit_fabric_init;
++	}
++
++	/*if (msmbus_coresight_init(pdev))
++		pr_warn("Coresight support absent for bus: %d\n", pdata->id);*/
++exit_fabric_init:
++	return ret;
++}
++
++static int msm_bus_init_clk(struct device *bus_dev,
++				struct msm_bus_node_device_type *pdata)
++{
++	unsigned int ctx;
++	int ret = 0;
++	struct msm_bus_node_device_type *node_dev = bus_dev->platform_data;
++
++	for (ctx = 0; ctx < NUM_CTX; ctx++) {
++		if (!IS_ERR_OR_NULL(pdata->clk[ctx].clk)) {
++			node_dev->clk[ctx].clk = pdata->clk[ctx].clk;
++			node_dev->clk[ctx].enable = false;
++			node_dev->clk[ctx].dirty = false;
++			MSM_BUS_ERR("%s: Valid node clk node %d ctx %d",
++				__func__, node_dev->node_info->id, ctx);
++		}
++	}
++
++	if (!IS_ERR_OR_NULL(pdata->qos_clk.clk)) {
++		node_dev->qos_clk.clk = pdata->qos_clk.clk;
++		node_dev->qos_clk.enable = false;
++		MSM_BUS_ERR("%s: Valid Iface clk node %d", __func__,
++						node_dev->node_info->id);
++	}
++
++	return ret;
++}
++
++static int msm_bus_copy_node_info(struct msm_bus_node_device_type *pdata,
++				struct device *bus_dev)
++{
++	int ret = 0;
++	struct msm_bus_node_info_type *node_info = NULL;
++	struct msm_bus_node_info_type *pdata_node_info = NULL;
++	struct msm_bus_node_device_type *bus_node = NULL;
++
++	bus_node = bus_dev->platform_data;
++
++	if (!bus_node || !pdata) {
++		ret = -ENXIO;
++		MSM_BUS_ERR("%s: Invalid pointers pdata %p, bus_node %p",
++			__func__, pdata, bus_node);
++		goto exit_copy_node_info;
++	}
++
++	node_info = bus_node->node_info;
++	pdata_node_info = pdata->node_info;
++
++	node_info->name = pdata_node_info->name;
++	node_info->id =  pdata_node_info->id;
++	node_info->bus_device_id = pdata_node_info->bus_device_id;
++	node_info->mas_rpm_id = pdata_node_info->mas_rpm_id;
++	node_info->slv_rpm_id = pdata_node_info->slv_rpm_id;
++	node_info->num_connections = pdata_node_info->num_connections;
++	node_info->num_blist = pdata_node_info->num_blist;
++	node_info->num_qports = pdata_node_info->num_qports;
++	node_info->buswidth = pdata_node_info->buswidth;
++	node_info->virt_dev = pdata_node_info->virt_dev;
++	node_info->is_fab_dev = pdata_node_info->is_fab_dev;
++	node_info->qos_params.mode = pdata_node_info->qos_params.mode;
++	node_info->qos_params.prio1 = pdata_node_info->qos_params.prio1;
++	node_info->qos_params.prio0 = pdata_node_info->qos_params.prio0;
++	node_info->qos_params.prio_lvl = pdata_node_info->qos_params.prio_lvl;
++	node_info->qos_params.prio_rd = pdata_node_info->qos_params.prio_rd;
++	node_info->qos_params.prio_wr = pdata_node_info->qos_params.prio_wr;
++	node_info->qos_params.gp = pdata_node_info->qos_params.gp;
++	node_info->qos_params.thmp = pdata_node_info->qos_params.thmp;
++	node_info->qos_params.ws = pdata_node_info->qos_params.ws;
++	node_info->qos_params.bw_buffer = pdata_node_info->qos_params.bw_buffer;
++	node_info->util_fact = pdata_node_info->util_fact;
++	node_info->vrail_comp = pdata_node_info->vrail_comp;
++
++	node_info->dev_connections = devm_kzalloc(bus_dev,
++			sizeof(struct device *) *
++				pdata_node_info->num_connections,
++			GFP_KERNEL);
++	if (!node_info->dev_connections) {
++		MSM_BUS_ERR("%s:Bus dev connections alloc failed\n", __func__);
++		ret = -ENOMEM;
++		goto exit_copy_node_info;
++	}
++
++	node_info->connections = devm_kzalloc(bus_dev,
++			sizeof(int) * pdata_node_info->num_connections,
++			GFP_KERNEL);
++	if (!node_info->connections) {
++		MSM_BUS_ERR("%s:Bus connections alloc failed\n", __func__);
++		devm_kfree(bus_dev, node_info->dev_connections);
++		ret = -ENOMEM;
++		goto exit_copy_node_info;
++	}
++
++	memcpy(node_info->connections,
++		pdata_node_info->connections,
++		sizeof(int) * pdata_node_info->num_connections);
++
++	node_info->black_connections = devm_kzalloc(bus_dev,
++			sizeof(struct device *) *
++				pdata_node_info->num_blist,
++			GFP_KERNEL);
++	if (!node_info->black_connections) {
++		MSM_BUS_ERR("%s: Bus black connections alloc failed\n",
++			__func__);
++		devm_kfree(bus_dev, node_info->dev_connections);
++		devm_kfree(bus_dev, node_info->connections);
++		ret = -ENOMEM;
++		goto exit_copy_node_info;
++	}
++
++	node_info->black_listed_connections = devm_kzalloc(bus_dev,
++			pdata_node_info->num_blist * sizeof(int),
++			GFP_KERNEL);
++	if (!node_info->black_listed_connections) {
++		MSM_BUS_ERR("%s:Bus black list connections alloc failed\n",
++					__func__);
++		devm_kfree(bus_dev, node_info->black_connections);
++		devm_kfree(bus_dev, node_info->dev_connections);
++		devm_kfree(bus_dev, node_info->connections);
++		ret = -ENOMEM;
++		goto exit_copy_node_info;
++	}
++
++	memcpy(node_info->black_listed_connections,
++		pdata_node_info->black_listed_connections,
++		sizeof(int) * pdata_node_info->num_blist);
++
++	node_info->qport = devm_kzalloc(bus_dev,
++			sizeof(int) * pdata_node_info->num_qports,
++			GFP_KERNEL);
++	if (!node_info->qport) {
++		MSM_BUS_ERR("%s:Bus qport allocation failed\n", __func__);
++		devm_kfree(bus_dev, node_info->dev_connections);
++		devm_kfree(bus_dev, node_info->connections);
++		devm_kfree(bus_dev, node_info->black_listed_connections);
++		ret = -ENOMEM;
++		goto exit_copy_node_info;
++	}
++
++	memcpy(node_info->qport,
++		pdata_node_info->qport,
++		sizeof(int) * pdata_node_info->num_qports);
++
++exit_copy_node_info:
++	return ret;
++}
++
++static struct device *msm_bus_device_init(
++			struct msm_bus_node_device_type *pdata)
++{
++	struct device *bus_dev = NULL;
++	struct msm_bus_node_device_type *bus_node = NULL;
++	struct msm_bus_node_info_type *node_info = NULL;
++	int ret = 0;
++
++	bus_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
++	if (!bus_dev) {
++		MSM_BUS_ERR("%s:Device alloc failed\n", __func__);
++		bus_dev = NULL;
++		goto exit_device_init;
++	}
++	/**
++	* Init here so we can use devm calls
++	*/
++	device_initialize(bus_dev);
++
++	bus_node = devm_kzalloc(bus_dev,
++			sizeof(struct msm_bus_node_device_type), GFP_KERNEL);
++	if (!bus_node) {
++		MSM_BUS_ERR("%s:Bus node alloc failed\n", __func__);
++		kfree(bus_dev);
++		bus_dev = NULL;
++		goto exit_device_init;
++	}
++
++	node_info = devm_kzalloc(bus_dev,
++			sizeof(struct msm_bus_node_info_type), GFP_KERNEL);
++	if (!node_info) {
++		MSM_BUS_ERR("%s:Bus node info alloc failed\n", __func__);
++		devm_kfree(bus_dev, bus_node);
++		kfree(bus_dev);
++		bus_dev = NULL;
++		goto exit_device_init;
++	}
++
++	bus_node->node_info = node_info;
++	bus_node->ap_owned = pdata->ap_owned;
++	bus_dev->platform_data = bus_node;
++
++	if (msm_bus_copy_node_info(pdata, bus_dev) < 0) {
++		devm_kfree(bus_dev, bus_node);
++		devm_kfree(bus_dev, node_info);
++		kfree(bus_dev);
++		bus_dev = NULL;
++		goto exit_device_init;
++	}
++
++	bus_dev->bus = &msm_bus_type;
++	dev_set_name(bus_dev, bus_node->node_info->name);
++
++	ret = device_add(bus_dev);
++	if (ret < 0) {
++		MSM_BUS_ERR("%s: Error registering device %d",
++				__func__, pdata->node_info->id);
++		devm_kfree(bus_dev, bus_node);
++		devm_kfree(bus_dev, node_info->dev_connections);
++		devm_kfree(bus_dev, node_info->connections);
++		devm_kfree(bus_dev, node_info->black_connections);
++		devm_kfree(bus_dev, node_info->black_listed_connections);
++		devm_kfree(bus_dev, node_info);
++		kfree(bus_dev);
++		bus_dev = NULL;
++		goto exit_device_init;
++	}
++	device_create_file(bus_dev, &dev_attr_vrail);
++
++exit_device_init:
++	return bus_dev;
++}
++
++static int msm_bus_setup_dev_conn(struct device *bus_dev, void *data)
++{
++	struct msm_bus_node_device_type *bus_node = NULL;
++	int ret = 0;
++	int j;
++
++	bus_node = bus_dev->platform_data;
++	if (!bus_node) {
++		MSM_BUS_ERR("%s: Can't get device info", __func__);
++		ret = -ENODEV;
++		goto exit_setup_dev_conn;
++	}
++
++	/* Setup parent bus device for this node */
++	if (!bus_node->node_info->is_fab_dev) {
++		struct device *bus_parent_device =
++			bus_find_device(&msm_bus_type, NULL,
++				(void *)&bus_node->node_info->bus_device_id,
++				msm_bus_device_match_adhoc);
++
++		if (!bus_parent_device) {
++			MSM_BUS_ERR("%s: Error finding parentdev %d parent %d",
++				__func__,
++				bus_node->node_info->id,
++				bus_node->node_info->bus_device_id);
++			ret = -ENXIO;
++			goto exit_setup_dev_conn;
++		}
++		bus_node->node_info->bus_device = bus_parent_device;
++	}
++
++	bus_node->node_info->is_traversed = false;
++
++	for (j = 0; j < bus_node->node_info->num_connections; j++) {
++		bus_node->node_info->dev_connections[j] =
++			bus_find_device(&msm_bus_type, NULL,
++				(void *)&bus_node->node_info->connections[j],
++				msm_bus_device_match_adhoc);
++
++		if (!bus_node->node_info->dev_connections[j]) {
++			MSM_BUS_ERR("%s: Error finding conn %d for device %d",
++				__func__, bus_node->node_info->connections[j],
++				 bus_node->node_info->id);
++			ret = -ENODEV;
++			goto exit_setup_dev_conn;
++		}
++	}
++
++	for (j = 0; j < bus_node->node_info->num_blist; j++) {
++		bus_node->node_info->black_connections[j] =
++			bus_find_device(&msm_bus_type, NULL,
++				(void *)&bus_node->node_info->
++				black_listed_connections[j],
++				msm_bus_device_match_adhoc);
++
++		if (!bus_node->node_info->black_connections[j]) {
++			MSM_BUS_ERR("%s: Error finding conn %d for device %d\n",
++				__func__, bus_node->node_info->
++				black_listed_connections[j],
++				bus_node->node_info->id);
++			ret = -ENODEV;
++			goto exit_setup_dev_conn;
++		}
++	}
++
++exit_setup_dev_conn:
++	return ret;
++}
++
++static int msm_bus_node_debug(struct device *bus_dev, void *data)
++{
++	int j;
++	int ret = 0;
++	struct msm_bus_node_device_type *bus_node = NULL;
++
++	bus_node = bus_dev->platform_data;
++	if (!bus_node) {
++		MSM_BUS_ERR("%s: Can't get device info", __func__);
++		ret = -ENODEV;
++		goto exit_node_debug;
++	}
++
++	MSM_BUS_DBG("Device = %d buswidth %u", bus_node->node_info->id,
++				bus_node->node_info->buswidth);
++	for (j = 0; j < bus_node->node_info->num_connections; j++) {
++		struct msm_bus_node_device_type *bdev =
++			(struct msm_bus_node_device_type *)
++			bus_node->node_info->dev_connections[j]->platform_data;
++		MSM_BUS_DBG("\n\t Connection[%d] %d", j, bdev->node_info->id);
++	}
++
++exit_node_debug:
++	return ret;
++}
++
++static int msm_bus_device_probe(struct platform_device *pdev)
++{
++	unsigned int i, ret;
++	struct msm_bus_device_node_registration *pdata;
++
++	/* If possible, get pdata from device-tree */
++	if (pdev->dev.of_node)
++		pdata = msm_bus_of_to_pdata(pdev);
++	else {
++		pdata = (struct msm_bus_device_node_registration *)pdev->
++			dev.platform_data;
++	}
++
++	if (IS_ERR_OR_NULL(pdata)) {
++		MSM_BUS_ERR("No platform data found");
++		ret = -ENODATA;
++		goto exit_device_probe;
++	}
++
++	for (i = 0; i < pdata->num_devices; i++) {
++		struct device *node_dev = NULL;
++
++		node_dev = msm_bus_device_init(&pdata->info[i]);
++
++		if (!node_dev) {
++			MSM_BUS_ERR("%s: Error during dev init for %d",
++				__func__, pdata->info[i].node_info->id);
++			ret = -ENXIO;
++			goto exit_device_probe;
++		}
++
++		ret = msm_bus_init_clk(node_dev, &pdata->info[i]);
++		/*Is this a fabric device ?*/
++		if (pdata->info[i].node_info->is_fab_dev) {
++			MSM_BUS_DBG("%s: %d is a fab", __func__,
++						pdata->info[i].node_info->id);
++			ret = msm_bus_fabric_init(node_dev, &pdata->info[i]);
++			if (ret) {
++				MSM_BUS_ERR("%s: Error intializing fab %d",
++					__func__, pdata->info[i].node_info->id);
++				goto exit_device_probe;
++			}
++		}
++	}
++
++	ret = bus_for_each_dev(&msm_bus_type, NULL, NULL,
++						msm_bus_setup_dev_conn);
++	if (ret) {
++		MSM_BUS_ERR("%s: Error setting up dev connections", __func__);
++		goto exit_device_probe;
++	}
++
++	ret = bus_for_each_dev(&msm_bus_type, NULL, NULL, msm_bus_dev_init_qos);
++	if (ret) {
++		MSM_BUS_ERR("%s: Error during qos init", __func__);
++		goto exit_device_probe;
++	}
++
++	bus_for_each_dev(&msm_bus_type, NULL, NULL, msm_bus_node_debug);
++
++	/* Register the arb layer ops */
++	msm_bus_arb_setops_adhoc(&arb_ops);
++	devm_kfree(&pdev->dev, pdata->info);
++	devm_kfree(&pdev->dev, pdata);
++exit_device_probe:
++	return ret;
++}
++
++static int msm_bus_device_rules_probe(struct platform_device *pdev)
++{
++	struct bus_rule_type *rule_data = NULL;
++	int num_rules = 0;
++
++	num_rules = msm_bus_of_get_static_rules(pdev, &rule_data);
++
++	if (!rule_data)
++		goto exit_rules_probe;
++
++	msm_rule_register(num_rules, rule_data, NULL);
++	static_rules.num_rules = num_rules;
++	static_rules.rules = rule_data;
++	pdev->dev.platform_data = &static_rules;
++
++exit_rules_probe:
++	return 0;
++}
++
++int msm_bus_device_rules_remove(struct platform_device *pdev)
++{
++	struct static_rules_type *static_rules = NULL;
++
++	static_rules = pdev->dev.platform_data;
++	if (static_rules)
++		msm_rule_unregister(static_rules->num_rules,
++					static_rules->rules, NULL);
++	return 0;
++}
++
++static int msm_bus_free_dev(struct device *dev, void *data)
++{
++	struct msm_bus_node_device_type *bus_node = NULL;
++
++	bus_node = dev->platform_data;
++
++	if (bus_node)
++		MSM_BUS_ERR("\n%s: Removing device %d", __func__,
++						bus_node->node_info->id);
++	device_unregister(dev);
++	return 0;
++}
++
++int msm_bus_device_remove(struct platform_device *pdev)
++{
++	bus_for_each_dev(&msm_bus_type, NULL, NULL, msm_bus_free_dev);
++	return 0;
++}
++
++static struct of_device_id rules_match[] = {
++	{.compatible = "qcom,msm-bus-static-bw-rules"},
++	{}
++};
++
++static struct platform_driver msm_bus_rules_driver = {
++	.probe = msm_bus_device_rules_probe,
++	.remove = msm_bus_device_rules_remove,
++	.driver = {
++		.name = "msm_bus_rules_device",
++		.owner = THIS_MODULE,
++		.of_match_table = rules_match,
++	},
++};
++
++static struct of_device_id fabric_match[] = {
++	{.compatible = "qcom,msm-bus-device"},
++	{}
++};
++
++static struct platform_driver msm_bus_device_driver = {
++	.probe = msm_bus_device_probe,
++	.remove = msm_bus_device_remove,
++	.driver = {
++		.name = "msm_bus_device",
++		.owner = THIS_MODULE,
++		.of_match_table = fabric_match,
++	},
++};
++
++int __init msm_bus_device_init_driver(void)
++{
++	int rc;
++
++	MSM_BUS_ERR("msm_bus_fabric_init_driver\n");
++	rc =  platform_driver_register(&msm_bus_device_driver);
++
++	if (rc) {
++		MSM_BUS_ERR("Failed to register bus device driver");
++		return rc;
++	}
++	return platform_driver_register(&msm_bus_rules_driver);
++}
++subsys_initcall(msm_bus_device_init_driver);
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_id.c
+@@ -0,0 +1,94 @@
++/* Copyright (c) 2013-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/module.h>
++#include "msm-bus.h"
++#include "msm-bus-board.h"
++#include "msm_bus_core.h"
++#include "msm_bus_noc.h"
++#include "msm_bus_bimc.h"
++
++static uint32_t master_iids[MSM_BUS_MASTER_LAST];
++static uint32_t slave_iids[MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY];
++
++static void msm_bus_assign_iids(struct msm_bus_fabric_registration
++	*fabreg, int fabid)
++{
++	int i;
++	for (i = 0; i < fabreg->len; i++) {
++		if (!fabreg->info[i].gateway) {
++			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
++			if (fabreg->info[i].id < SLAVE_ID_KEY) {
++				if (fabreg->info[i].id >= MSM_BUS_MASTER_LAST) {
++					WARN(1, "id %d exceeds array size!\n",
++						fabreg->info[i].id);
++					continue;
++				}
++
++				master_iids[fabreg->info[i].id] =
++					fabreg->info[i].priv_id;
++			} else {
++				if ((fabreg->info[i].id - SLAVE_ID_KEY) >=
++					(MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY)) {
++					WARN(1, "id %d exceeds array size!\n",
++						fabreg->info[i].id);
++					continue;
++				}
++
++				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
++					= fabreg->info[i].priv_id;
++			}
++		} else {
++			fabreg->info[i].priv_id = fabreg->info[i].id;
++		}
++	}
++}
++
++static int msm_bus_get_iid(int id)
++{
++	if ((id < SLAVE_ID_KEY && id >= MSM_BUS_MASTER_LAST) ||
++		id >= MSM_BUS_SLAVE_LAST) {
++		MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
++		return -EINVAL;
++	}
++
++	return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
++		slave_iids[id - SLAVE_ID_KEY]), id);
++}
++
++static struct msm_bus_board_algorithm msm_bus_id_algo = {
++	.get_iid = msm_bus_get_iid,
++	.assign_iids = msm_bus_assign_iids,
++};
++
++int msm_bus_board_rpm_get_il_ids(uint16_t *id)
++{
++	return -ENXIO;
++}
++
++void msm_bus_board_init(struct msm_bus_fabric_registration *pdata)
++{
++	pdata->board_algo = &msm_bus_id_algo;
++}
++
++void msm_bus_board_set_nfab(struct msm_bus_fabric_registration *pdata,
++	int nfab)
++{
++	if (nfab <= 0)
++		return;
++
++	msm_bus_id_algo.board_nfab = nfab;
++}
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_noc.c
+@@ -0,0 +1,770 @@
++/* Copyright (c) 2012-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#define pr_fmt(fmt) "AXI: NOC: %s(): " fmt, __func__
++
++#include <linux/slab.h>
++#include <linux/io.h>
++#include "msm-bus-board.h"
++#include "msm_bus_core.h"
++#include "msm_bus_noc.h"
++#include "msm_bus_adhoc.h"
++
++/* NOC_QOS generic */
++#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
++#define SAT_SCALE 16	/* 16 bytes minimum for saturation */
++#define BW_SCALE  256	/* 1/256 byte per cycle unit */
++#define QOS_DEFAULT_BASEOFFSET		0x00003000
++#define QOS_DEFAULT_DELTA		0x80
++#define MAX_BW_FIELD (NOC_QOS_BWn_BW_BMSK >> NOC_QOS_BWn_BW_SHFT)
++#define MAX_SAT_FIELD (NOC_QOS_SATn_SAT_BMSK >> NOC_QOS_SATn_SAT_SHFT)
++
++#define NOC_QOS_REG_BASE(b, o)		((b) + (o))
++
++#define NOC_QOS_ID_COREIDn_ADDR(b, o, n, d) \
++	(NOC_QOS_REG_BASE(b, o) + (d) * (n))
++enum noc_qos_id_coreidn {
++	NOC_QOS_ID_COREIDn_RMSK			= 0xffffffff,
++	NOC_QOS_ID_COREIDn_MAXn			= 32,
++	NOC_QOS_ID_COREIDn_CORECHSUM_BMSK	= 0xffffff00,
++	NOC_QOS_ID_COREIDn_CORECHSUM_SHFT	= 0x8,
++	NOC_QOS_ID_COREIDn_CORETYPEID_BMSK	= 0xff,
++	NOC_QOS_ID_COREIDn_CORETYPEID_SHFT	= 0x0,
++};
++
++#define NOC_QOS_ID_REVISIONIDn_ADDR(b, o, n, d) \
++	(NOC_QOS_REG_BASE(b, o) + 0x4 + (d) * (n))
++enum noc_qos_id_revisionidn {
++	NOC_QOS_ID_REVISIONIDn_RMSK		= 0xffffffff,
++	NOC_QOS_ID_REVISIONIDn_MAXn		= 32,
++	NOC_QOS_ID_REVISIONIDn_FLEXNOCID_BMSK	= 0xffffff00,
++	NOC_QOS_ID_REVISIONIDn_FLEXNOCID_SHFT	= 0x8,
++	NOC_QOS_ID_REVISIONIDn_USERID_BMSK	= 0xff,
++	NOC_QOS_ID_REVISIONIDn_USERID_SHFT	= 0x0,
++};
++
++#define NOC_QOS_PRIORITYn_ADDR(b, o, n, d)	\
++	(NOC_QOS_REG_BASE(b, o) + 0x8 + (d) * (n))
++enum noc_qos_id_priorityn {
++	NOC_QOS_PRIORITYn_RMSK		= 0x0000000f,
++	NOC_QOS_PRIORITYn_MAXn		= 32,
++	NOC_QOS_PRIORITYn_P1_BMSK	= 0xc,
++	NOC_QOS_PRIORITYn_P1_SHFT	= 0x2,
++	NOC_QOS_PRIORITYn_P0_BMSK	= 0x3,
++	NOC_QOS_PRIORITYn_P0_SHFT	= 0x0,
++};
++
++#define NOC_QOS_MODEn_ADDR(b, o, n, d) \
++	(NOC_QOS_REG_BASE(b, o) + 0xC + (d) * (n))
++enum noc_qos_id_moden_rmsk {
++	NOC_QOS_MODEn_RMSK		= 0x00000003,
++	NOC_QOS_MODEn_MAXn		= 32,
++	NOC_QOS_MODEn_MODE_BMSK		= 0x3,
++	NOC_QOS_MODEn_MODE_SHFT		= 0x0,
++};
++
++#define NOC_QOS_BWn_ADDR(b, o, n, d) \
++	(NOC_QOS_REG_BASE(b, o) + 0x10 + (d) * (n))
++enum noc_qos_id_bwn {
++	NOC_QOS_BWn_RMSK		= 0x0000ffff,
++	NOC_QOS_BWn_MAXn		= 32,
++	NOC_QOS_BWn_BW_BMSK		= 0xffff,
++	NOC_QOS_BWn_BW_SHFT		= 0x0,
++};
++
++/* QOS Saturation registers */
++#define NOC_QOS_SATn_ADDR(b, o, n, d) \
++	(NOC_QOS_REG_BASE(b, o) + 0x14 + (d) * (n))
++enum noc_qos_id_saturationn {
++	NOC_QOS_SATn_RMSK		= 0x000003ff,
++	NOC_QOS_SATn_MAXn		= 32,
++	NOC_QOS_SATn_SAT_BMSK		= 0x3ff,
++	NOC_QOS_SATn_SAT_SHFT		= 0x0,
++};
++
++static int noc_div(uint64_t *a, uint32_t b)
++{
++	if ((*a > 0) && (*a < b))
++		return 1;
++	else
++		return do_div(*a, b);
++}
++
++/**
++ * Calculates bw hardware is using from register values
++ * bw returned is in bytes/sec
++ */
++static uint64_t noc_bw(uint32_t bw_field, uint32_t qos_freq)
++{
++	uint64_t res;
++	uint32_t rem, scale;
++
++	res = 2 * qos_freq * bw_field;
++	scale = BW_SCALE * 1000;
++	rem = noc_div(&res, scale);
++	MSM_BUS_DBG("NOC: Calculated bw: %llu\n", res * 1000000ULL);
++	return res * 1000000ULL;
++}
++
++static uint32_t noc_bw_ceil(long int bw_field, uint32_t qos_freq)
++{
++	uint64_t bw_temp = 2 * qos_freq * bw_field;
++	uint32_t scale = 1000 * BW_SCALE;
++	noc_div(&bw_temp, scale);
++	return bw_temp * 1000000;
++}
++#define MAX_BW(timebase) noc_bw_ceil(MAX_BW_FIELD, (timebase))
++
++/**
++ * Calculates ws hardware is using from register values
++ * ws returned is in nanoseconds
++ */
++static uint32_t noc_ws(uint64_t bw, uint32_t sat, uint32_t qos_freq)
++{
++	if (bw && qos_freq) {
++		uint32_t bwf = bw * qos_freq;
++		uint64_t scale = 1000000000000LL * BW_SCALE *
++			SAT_SCALE * sat;
++		noc_div(&scale, bwf);
++		MSM_BUS_DBG("NOC: Calculated ws: %llu\n", scale);
++		return scale;
++	}
++
++	return 0;
++}
++#define MAX_WS(bw, timebase) noc_ws((bw), MAX_SAT_FIELD, (timebase))
++
++/* Calculate bandwidth field value for requested bandwidth  */
++static uint32_t noc_bw_field(uint64_t bw, uint32_t qos_freq)
++{
++	uint32_t bw_field = 0;
++
++	if (bw) {
++		uint32_t rem;
++		uint64_t bw_capped = min_t(uint64_t, bw, MAX_BW(qos_freq));
++		uint64_t bwc = bw_capped * BW_SCALE;
++		uint64_t qf = 2 * qos_freq * 1000;
++
++		rem = noc_div(&bwc, qf);
++		bw_field = (uint32_t)min_t(uint64_t, bwc, MAX_BW_FIELD);
++	}
++
++	MSM_BUS_DBG("NOC: bw_field: %u\n", bw_field);
++	return bw_field;
++}
++
++static uint32_t noc_sat_field(uint64_t bw, uint32_t ws, uint32_t qos_freq)
++{
++	uint32_t sat_field = 0, win;
++
++	if (bw) {
++		/* Limit to max bw and scale bw to 100 KB increments */
++		uint64_t tbw, tscale;
++		uint64_t bw_scaled = min_t(uint64_t, bw, MAX_BW(qos_freq));
++		uint32_t rem = noc_div(&bw_scaled, 100000);
++
++		/**
++		 * Calculate saturation from windows size.
++		 * WS must be at least one arb period.
++		 * Saturation must not exceed max field size
++		 *
++		 * Bandwidth is in 100KB increments
++		 * Window size is in ns
++		 * qos_freq is in KHz
++		 */
++		win = max(ws, 1000000 / qos_freq);
++		tbw = bw_scaled * win * qos_freq;
++		tscale = 10000000ULL * BW_SCALE * SAT_SCALE;
++		rem = noc_div(&tbw, tscale);
++		sat_field = (uint32_t)min_t(uint64_t, tbw, MAX_SAT_FIELD);
++	}
++
++	MSM_BUS_DBG("NOC: sat_field: %d\n", sat_field);
++	return sat_field;
++}
++
++static void noc_set_qos_mode(void __iomem *base, uint32_t qos_off,
++		uint32_t mport, uint32_t qos_delta, uint8_t mode,
++		uint8_t perm_mode)
++{
++	if (mode < NOC_QOS_MODE_MAX &&
++		((1 << mode) & perm_mode)) {
++		uint32_t reg_val;
++
++		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
++			mport, qos_delta)) & NOC_QOS_MODEn_RMSK;
++		writel_relaxed(((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) |
++			(mode & NOC_QOS_MODEn_MODE_BMSK)),
++			NOC_QOS_MODEn_ADDR(base, qos_off, mport, qos_delta));
++	}
++	/* Ensure qos mode is set before exiting */
++	wmb();
++}
++
++static void noc_set_qos_priority(void __iomem *base, uint32_t qos_off,
++		uint32_t mport, uint32_t qos_delta,
++		struct msm_bus_noc_qos_priority *priority)
++{
++	uint32_t reg_val, val;
++
++	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport,
++		qos_delta)) & NOC_QOS_PRIORITYn_RMSK;
++	val = priority->p1 << NOC_QOS_PRIORITYn_P1_SHFT;
++	writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P1_BMSK))) |
++		(val & NOC_QOS_PRIORITYn_P1_BMSK)),
++		NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, qos_delta));
++
++	reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport,
++								qos_delta))
++		& NOC_QOS_PRIORITYn_RMSK;
++	writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P0_BMSK))) |
++		(priority->p0 & NOC_QOS_PRIORITYn_P0_BMSK)),
++		NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, qos_delta));
++	/* Ensure qos priority is set before exiting */
++	wmb();
++}
++
++static void msm_bus_noc_set_qos_bw(void __iomem *base, uint32_t qos_off,
++		uint32_t qos_freq, uint32_t mport, uint32_t qos_delta,
++		uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw)
++{
++	uint32_t reg_val, val, mode;
++
++	if (!qos_freq) {
++		MSM_BUS_DBG("Zero QoS Freq\n");
++		return;
++	}
++
++
++	/* If Limiter or Regulator modes are not supported, bw not available*/
++	if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
++		NOC_QOS_PERM_MODE_REGULATOR)) {
++		uint32_t bw_val = noc_bw_field(qbw->bw, qos_freq);
++		uint32_t sat_val = noc_sat_field(qbw->bw, qbw->ws,
++			qos_freq);
++
++		MSM_BUS_DBG("NOC: BW: perm_mode: %d bw_val: %d, sat_val: %d\n",
++			perm_mode, bw_val, sat_val);
++		/*
++		 * If in Limiter/Regulator mode, first go to fixed mode.
++		 * Clear QoS accumulator
++		 **/
++		mode = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
++			mport, qos_delta)) & NOC_QOS_MODEn_MODE_BMSK;
++		if (mode == NOC_QOS_MODE_REGULATOR || mode ==
++			NOC_QOS_MODE_LIMITER) {
++			reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(
++				base, qos_off, mport, qos_delta));
++			val = NOC_QOS_MODE_FIXED;
++			writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
++				| (val & NOC_QOS_MODEn_MODE_BMSK),
++				NOC_QOS_MODEn_ADDR(base, qos_off, mport,
++								qos_delta));
++		}
++
++		reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(base, qos_off, mport,
++								qos_delta));
++		val = bw_val << NOC_QOS_BWn_BW_SHFT;
++		writel_relaxed(((reg_val & (~(NOC_QOS_BWn_BW_BMSK))) |
++			(val & NOC_QOS_BWn_BW_BMSK)),
++			NOC_QOS_BWn_ADDR(base, qos_off, mport, qos_delta));
++
++		MSM_BUS_DBG("NOC: BW: Wrote value: 0x%x\n", ((reg_val &
++			(~NOC_QOS_BWn_BW_BMSK)) | (val &
++			NOC_QOS_BWn_BW_BMSK)));
++
++		reg_val = readl_relaxed(NOC_QOS_SATn_ADDR(base, qos_off,
++			mport, qos_delta));
++		val = sat_val << NOC_QOS_SATn_SAT_SHFT;
++		writel_relaxed(((reg_val & (~(NOC_QOS_SATn_SAT_BMSK))) |
++			(val & NOC_QOS_SATn_SAT_BMSK)),
++			NOC_QOS_SATn_ADDR(base, qos_off, mport, qos_delta));
++
++		MSM_BUS_DBG("NOC: SAT: Wrote value: 0x%x\n", ((reg_val &
++			(~NOC_QOS_SATn_SAT_BMSK)) | (val &
++			NOC_QOS_SATn_SAT_BMSK)));
++
++		/* Set mode back to what it was initially */
++		reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
++			mport, qos_delta));
++		writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
++			| (mode & NOC_QOS_MODEn_MODE_BMSK),
++			NOC_QOS_MODEn_ADDR(base, qos_off, mport, qos_delta));
++		/* Ensure that all writes for bandwidth registers have
++		 * completed before returning
++		 */
++		wmb();
++	}
++}
++
++uint8_t msm_bus_noc_get_qos_mode(void __iomem *base, uint32_t qos_off,
++	uint32_t mport, uint32_t qos_delta, uint32_t mode, uint32_t perm_mode)
++{
++	if (NOC_QOS_MODES_ALL_PERM == perm_mode)
++		return readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
++			mport, qos_delta)) & NOC_QOS_MODEn_MODE_BMSK;
++	else
++		return 31 - __CLZ(mode &
++			NOC_QOS_MODES_ALL_PERM);
++}
++
++void msm_bus_noc_get_qos_priority(void __iomem *base, uint32_t qos_off,
++	uint32_t mport, uint32_t qos_delta,
++	struct msm_bus_noc_qos_priority *priority)
++{
++	priority->p1 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off,
++		mport, qos_delta)) & NOC_QOS_PRIORITYn_P1_BMSK) >>
++		NOC_QOS_PRIORITYn_P1_SHFT;
++
++	priority->p0 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off,
++		mport, qos_delta)) & NOC_QOS_PRIORITYn_P0_BMSK) >>
++		NOC_QOS_PRIORITYn_P0_SHFT;
++}
++
++void msm_bus_noc_get_qos_bw(void __iomem *base, uint32_t qos_off,
++	uint32_t qos_freq,
++	uint32_t mport, uint32_t qos_delta, uint8_t perm_mode,
++	struct msm_bus_noc_qos_bw *qbw)
++{
++	if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
++		NOC_QOS_PERM_MODE_REGULATOR)) {
++		uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR(
++			base, qos_off, mport, qos_delta)) & NOC_QOS_BWn_BW_BMSK;
++		uint32_t sat = readl_relaxed(NOC_QOS_SATn_ADDR(
++			base, qos_off, mport, qos_delta))
++						& NOC_QOS_SATn_SAT_BMSK;
++
++		qbw->bw = noc_bw(bw_val, qos_freq);
++		qbw->ws = noc_ws(qbw->bw, sat, qos_freq);
++	} else {
++		qbw->bw = 0;
++		qbw->ws = 0;
++	}
++}
++
++static int msm_bus_noc_mas_init(struct msm_bus_noc_info *ninfo,
++	struct msm_bus_inode_info *info)
++{
++	int i;
++	struct msm_bus_noc_qos_priority *prio;
++	prio = kzalloc(sizeof(struct msm_bus_noc_qos_priority),
++		GFP_KERNEL);
++	if (!prio) {
++		MSM_BUS_WARN("Couldn't alloc prio data for node: %d\n",
++			info->node_info->id);
++		return -ENOMEM;
++	}
++
++	prio->read_prio = info->node_info->prio_rd;
++	prio->write_prio = info->node_info->prio_wr;
++	prio->p1 = info->node_info->prio1;
++	prio->p0 = info->node_info->prio0;
++	info->hw_data = (void *)prio;
++
++	if (!info->node_info->qport) {
++		MSM_BUS_DBG("No QoS Ports to init\n");
++		return 0;
++	}
++
++	for (i = 0; i < info->node_info->num_mports; i++) {
++		if (info->node_info->mode != NOC_QOS_MODE_BYPASS) {
++			noc_set_qos_priority(ninfo->base, ninfo->qos_baseoffset,
++				info->node_info->qport[i], ninfo->qos_delta,
++				prio);
++
++			if (info->node_info->mode != NOC_QOS_MODE_FIXED) {
++				struct msm_bus_noc_qos_bw qbw;
++				qbw.ws = info->node_info->ws;
++				qbw.bw = 0;
++				msm_bus_noc_set_qos_bw(ninfo->base,
++					ninfo->qos_baseoffset,
++					ninfo->qos_freq, info->node_info->
++					qport[i], ninfo->qos_delta,
++					info->node_info->perm_mode,
++					&qbw);
++			}
++		}
++
++		noc_set_qos_mode(ninfo->base, ninfo->qos_baseoffset,
++			info->node_info->qport[i], ninfo->qos_delta,
++			info->node_info->mode,
++			info->node_info->perm_mode);
++	}
++
++	return 0;
++}
++
++static void msm_bus_noc_node_init(void *hw_data,
++	struct msm_bus_inode_info *info)
++{
++	struct msm_bus_noc_info *ninfo =
++		(struct msm_bus_noc_info *)hw_data;
++
++	if (!IS_SLAVE(info->node_info->priv_id))
++		if (info->node_info->hw_sel != MSM_BUS_RPM)
++			msm_bus_noc_mas_init(ninfo, info);
++}
++
++static int msm_bus_noc_allocate_commit_data(struct msm_bus_fabric_registration
++	*fab_pdata, void **cdata, int ctx)
++{
++	struct msm_bus_noc_commit **cd = (struct msm_bus_noc_commit **)cdata;
++	struct msm_bus_noc_info *ninfo =
++		(struct msm_bus_noc_info *)fab_pdata->hw_data;
++
++	*cd = kzalloc(sizeof(struct msm_bus_noc_commit), GFP_KERNEL);
++	if (!*cd) {
++		MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
++		return -ENOMEM;
++	}
++
++	(*cd)->mas = ninfo->cdata[ctx].mas;
++	(*cd)->slv = ninfo->cdata[ctx].slv;
++
++	return 0;
++}
++
++static void *msm_bus_noc_allocate_noc_data(struct platform_device *pdev,
++	struct msm_bus_fabric_registration *fab_pdata)
++{
++	struct resource *noc_mem;
++	struct resource *noc_io;
++	struct msm_bus_noc_info *ninfo;
++	int i;
++
++	ninfo = kzalloc(sizeof(struct msm_bus_noc_info), GFP_KERNEL);
++	if (!ninfo) {
++		MSM_BUS_DBG("Couldn't alloc mem for noc info\n");
++		return NULL;
++	}
++
++	ninfo->nmasters = fab_pdata->nmasters;
++	ninfo->nqos_masters = fab_pdata->nmasters;
++	ninfo->nslaves = fab_pdata->nslaves;
++	ninfo->qos_freq = fab_pdata->qos_freq;
++
++	if (!fab_pdata->qos_baseoffset)
++		ninfo->qos_baseoffset = QOS_DEFAULT_BASEOFFSET;
++	else
++		ninfo->qos_baseoffset = fab_pdata->qos_baseoffset;
++
++	if (!fab_pdata->qos_delta)
++		ninfo->qos_delta = QOS_DEFAULT_DELTA;
++	else
++		ninfo->qos_delta = fab_pdata->qos_delta;
++
++	ninfo->mas_modes = kzalloc(sizeof(uint32_t) * fab_pdata->nmasters,
++		GFP_KERNEL);
++	if (!ninfo->mas_modes) {
++		MSM_BUS_DBG("Couldn't alloc mem for noc master-modes\n");
++		kfree(ninfo);
++		return NULL;
++	}
++
++	for (i = 0; i < NUM_CTX; i++) {
++		ninfo->cdata[i].mas = kzalloc(sizeof(struct
++			msm_bus_node_hw_info) * fab_pdata->nmasters * 2,
++			GFP_KERNEL);
++		if (!ninfo->cdata[i].mas) {
++			MSM_BUS_DBG("Couldn't alloc mem for noc master-bw\n");
++			kfree(ninfo->mas_modes);
++			kfree(ninfo);
++			return NULL;
++		}
++
++		ninfo->cdata[i].slv = kzalloc(sizeof(struct
++			msm_bus_node_hw_info) * fab_pdata->nslaves * 2,
++			GFP_KERNEL);
++		if (!ninfo->cdata[i].slv) {
++			MSM_BUS_DBG("Couldn't alloc mem for noc master-bw\n");
++			kfree(ninfo->cdata[i].mas);
++			goto err;
++		}
++	}
++
++	/* If it's a virtual fabric, don't get memory info */
++	if (fab_pdata->virt)
++		goto skip_mem;
++
++	noc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	if (!noc_mem && !fab_pdata->virt) {
++		MSM_BUS_ERR("Cannot get NoC Base address\n");
++		goto err;
++	}
++
++	noc_io = request_mem_region(noc_mem->start,
++			resource_size(noc_mem), pdev->name);
++	if (!noc_io) {
++		MSM_BUS_ERR("NoC memory unavailable\n");
++		goto err;
++	}
++
++	ninfo->base = ioremap(noc_mem->start, resource_size(noc_mem));
++	if (!ninfo->base) {
++		MSM_BUS_ERR("IOremap failed for NoC!\n");
++		release_mem_region(noc_mem->start, resource_size(noc_mem));
++		goto err;
++	}
++
++skip_mem:
++	fab_pdata->hw_data = (void *)ninfo;
++	return (void *)ninfo;
++
++err:
++	kfree(ninfo->mas_modes);
++	kfree(ninfo);
++	return NULL;
++}
++
++static void free_commit_data(void *cdata)
++{
++	struct msm_bus_noc_commit *cd = (struct msm_bus_noc_commit *)cdata;
++
++	kfree(cd->mas);
++	kfree(cd->slv);
++	kfree(cd);
++}
++
++static bool msm_bus_noc_update_bw_reg(int mode)
++{
++	bool ret = false;
++
++	if ((mode == NOC_QOS_MODE_LIMITER) ||
++			(mode == NOC_QOS_MODE_REGULATOR))
++			ret = true;
++
++	return ret;
++}
++
++static void msm_bus_noc_update_bw(struct msm_bus_inode_info *hop,
++	struct msm_bus_inode_info *info,
++	struct msm_bus_fabric_registration *fab_pdata,
++	void *sel_cdata, int *master_tiers,
++	int64_t add_bw)
++{
++	struct msm_bus_noc_info *ninfo;
++	struct msm_bus_noc_qos_bw qos_bw;
++	int i, ports;
++	int64_t bw;
++	struct msm_bus_noc_commit *sel_cd =
++		(struct msm_bus_noc_commit *)sel_cdata;
++
++	ninfo = (struct msm_bus_noc_info *)fab_pdata->hw_data;
++	if (!ninfo->qos_freq) {
++		MSM_BUS_DBG("NOC: No qos frequency to update bw\n");
++		return;
++	}
++
++	if (info->node_info->num_mports == 0) {
++		MSM_BUS_DBG("NOC: Skip Master BW\n");
++		goto skip_mas_bw;
++	}
++
++	ports = info->node_info->num_mports;
++	bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
++
++	MSM_BUS_DBG("NOC: Update bw for: %d: %lld\n",
++		info->node_info->priv_id, add_bw);
++	for (i = 0; i < ports; i++) {
++		sel_cd->mas[info->node_info->masterp[i]].bw += bw;
++		sel_cd->mas[info->node_info->masterp[i]].hw_id =
++			info->node_info->mas_hw_id;
++		MSM_BUS_DBG("NOC: Update mas_bw: ID: %d, BW: %llu ports:%d\n",
++			info->node_info->priv_id,
++			sel_cd->mas[info->node_info->masterp[i]].bw,
++			ports);
++		/* Check if info is a shared master.
++		 * If it is, mark it dirty
++		 * If it isn't, then set QOS Bandwidth
++		 **/
++		if (info->node_info->hw_sel == MSM_BUS_RPM)
++			sel_cd->mas[info->node_info->masterp[i]].dirty = 1;
++		else {
++			if (!info->node_info->qport) {
++				MSM_BUS_DBG("No qos ports to update!\n");
++				break;
++			}
++
++			if (!(info->node_info->mode == NOC_QOS_MODE_REGULATOR)
++					|| (info->node_info->mode ==
++						NOC_QOS_MODE_LIMITER)) {
++				MSM_BUS_DBG("Skip QoS reg programming\n");
++				break;
++			}
++			qos_bw.bw = sel_cd->mas[info->node_info->masterp[i]].
++				bw;
++			qos_bw.ws = info->node_info->ws;
++			msm_bus_noc_set_qos_bw(ninfo->base,
++				ninfo->qos_baseoffset,
++				ninfo->qos_freq,
++				info->node_info->qport[i], ninfo->qos_delta,
++				info->node_info->perm_mode, &qos_bw);
++			MSM_BUS_DBG("NOC: QoS: Update mas_bw: ws: %u\n",
++				qos_bw.ws);
++		}
++	}
++
++skip_mas_bw:
++	ports = hop->node_info->num_sports;
++	for (i = 0; i < ports; i++) {
++		sel_cd->slv[hop->node_info->slavep[i]].bw += add_bw;
++		sel_cd->slv[hop->node_info->slavep[i]].hw_id =
++			hop->node_info->slv_hw_id;
++		MSM_BUS_DBG("NOC: Update slave_bw for ID: %d -> %llu\n",
++			hop->node_info->priv_id,
++			sel_cd->slv[hop->node_info->slavep[i]].bw);
++		MSM_BUS_DBG("NOC: Update slave_bw for hw_id: %d, index: %d\n",
++			hop->node_info->slv_hw_id, hop->node_info->slavep[i]);
++		/* Check if hop is a shared slave.
++		 * If it is, mark it dirty
++		 * If it isn't, then nothing to be done as the
++		 * slaves are in bypass mode.
++		 **/
++		if (hop->node_info->hw_sel == MSM_BUS_RPM)
++			sel_cd->slv[hop->node_info->slavep[i]].dirty = 1;
++	}
++}
++
++static int msm_bus_noc_commit(struct msm_bus_fabric_registration
++	*fab_pdata, void *hw_data, void **cdata)
++{
++	MSM_BUS_DBG("\nReached NOC Commit\n");
++	msm_bus_remote_hw_commit(fab_pdata, hw_data, cdata);
++	return 0;
++}
++
++static int msm_bus_noc_port_halt(uint32_t haltid, uint8_t mport)
++{
++	return 0;
++}
++
++static int msm_bus_noc_port_unhalt(uint32_t haltid, uint8_t mport)
++{
++	return 0;
++}
++
++static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info,
++				void __iomem *qos_base,
++				uint32_t qos_off, uint32_t qos_delta,
++				uint32_t qos_freq)
++{
++	struct msm_bus_noc_qos_priority prio;
++	int ret = 0;
++	int i;
++
++	prio.p1 = info->node_info->qos_params.prio1;
++	prio.p0 = info->node_info->qos_params.prio0;
++
++	if (!info->node_info->qport) {
++		MSM_BUS_DBG("No QoS Ports to init\n");
++		ret = 0;
++		goto err_qos_init;
++	}
++
++	for (i = 0; i < info->node_info->num_qports; i++) {
++		if (info->node_info->qos_params.mode != NOC_QOS_MODE_BYPASS) {
++			noc_set_qos_priority(qos_base, qos_off,
++					info->node_info->qport[i], qos_delta,
++					&prio);
++
++			if (info->node_info->qos_params.mode !=
++							NOC_QOS_MODE_FIXED) {
++				struct msm_bus_noc_qos_bw qbw;
++				qbw.ws = info->node_info->qos_params.ws;
++				qbw.bw = 0;
++				msm_bus_noc_set_qos_bw(qos_base, qos_off,
++					qos_freq,
++					info->node_info->qport[i],
++					qos_delta,
++					info->node_info->qos_params.mode,
++					&qbw);
++			}
++		}
++
++		noc_set_qos_mode(qos_base, qos_off, info->node_info->qport[i],
++				qos_delta, info->node_info->qos_params.mode,
++				(1 << info->node_info->qos_params.mode));
++	}
++err_qos_init:
++	return ret;
++}
++
++static int msm_bus_noc_set_bw(struct msm_bus_node_device_type *dev,
++				void __iomem *qos_base,
++				uint32_t qos_off, uint32_t qos_delta,
++				uint32_t qos_freq)
++{
++	int ret = 0;
++	uint64_t bw = 0;
++	int i;
++	struct msm_bus_node_info_type *info = dev->node_info;
++
++	if (info && info->num_qports &&
++		((info->qos_params.mode == NOC_QOS_MODE_REGULATOR) ||
++		(info->qos_params.mode ==
++			NOC_QOS_MODE_LIMITER))) {
++		struct msm_bus_noc_qos_bw qos_bw;
++
++		bw = msm_bus_div64(info->num_qports,
++				dev->node_ab.ab[DUAL_CTX]);
++
++		for (i = 0; i < info->num_qports; i++) {
++			if (!info->qport) {
++				MSM_BUS_DBG("No qos ports to update!\n");
++				break;
++			}
++
++			qos_bw.bw = bw;
++			qos_bw.ws = info->qos_params.ws;
++			msm_bus_noc_set_qos_bw(qos_base, qos_off, qos_freq,
++				info->qport[i], qos_delta,
++				info->qos_params.mode, &qos_bw);
++			MSM_BUS_DBG("NOC: QoS: Update mas_bw: ws: %u\n",
++				qos_bw.ws);
++		}
++	}
++	return ret;
++}
++int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata,
++	struct msm_bus_hw_algorithm *hw_algo)
++{
++	/* Set interleaving to true by default */
++	pdata->il_flag = true;
++	hw_algo->allocate_commit_data = msm_bus_noc_allocate_commit_data;
++	hw_algo->allocate_hw_data = msm_bus_noc_allocate_noc_data;
++	hw_algo->node_init = msm_bus_noc_node_init;
++	hw_algo->free_commit_data = free_commit_data;
++	hw_algo->update_bw = msm_bus_noc_update_bw;
++	hw_algo->commit = msm_bus_noc_commit;
++	hw_algo->port_halt = msm_bus_noc_port_halt;
++	hw_algo->port_unhalt = msm_bus_noc_port_unhalt;
++	hw_algo->update_bw_reg = msm_bus_noc_update_bw_reg;
++	hw_algo->config_master = NULL;
++	hw_algo->config_limiter = NULL;
++
++	return 0;
++}
++
++int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev)
++{
++	if (!bus_dev)
++		return -ENODEV;
++	else {
++		bus_dev->fabdev->noc_ops.qos_init = msm_bus_noc_qos_init;
++		bus_dev->fabdev->noc_ops.set_bw = msm_bus_noc_set_bw;
++		bus_dev->fabdev->noc_ops.limit_mport = NULL;
++		bus_dev->fabdev->noc_ops.update_bw_reg =
++						msm_bus_noc_update_bw_reg;
++	}
++	return 0;
++}
++EXPORT_SYMBOL(msm_bus_noc_set_ops);
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_noc.h
+@@ -0,0 +1,76 @@
++/* Copyright (c) 2012-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _ARCH_ARM_MACH_MSM_BUS_BIMC_H
++#define _ARCH_ARM_MACH_MSM_BUS_BIMC_H
++
++enum msm_bus_noc_qos_mode_type {
++	NOC_QOS_MODE_FIXED = 0,
++	NOC_QOS_MODE_LIMITER,
++	NOC_QOS_MODE_BYPASS,
++	NOC_QOS_MODE_REGULATOR,
++	NOC_QOS_MODE_MAX,
++};
++
++enum msm_bus_noc_qos_mode_perm {
++	NOC_QOS_PERM_MODE_FIXED = (1 << NOC_QOS_MODE_FIXED),
++	NOC_QOS_PERM_MODE_LIMITER = (1 << NOC_QOS_MODE_LIMITER),
++	NOC_QOS_PERM_MODE_BYPASS = (1 << NOC_QOS_MODE_BYPASS),
++	NOC_QOS_PERM_MODE_REGULATOR = (1 << NOC_QOS_MODE_REGULATOR),
++};
++
++#define NOC_QOS_MODES_ALL_PERM (NOC_QOS_PERM_MODE_FIXED | \
++	NOC_QOS_PERM_MODE_LIMITER | NOC_QOS_PERM_MODE_BYPASS | \
++	NOC_QOS_PERM_MODE_REGULATOR)
++
++struct msm_bus_noc_commit {
++	struct msm_bus_node_hw_info *mas;
++	struct msm_bus_node_hw_info *slv;
++};
++
++struct msm_bus_noc_info {
++	void __iomem *base;
++	uint32_t base_addr;
++	uint32_t nmasters;
++	uint32_t nqos_masters;
++	uint32_t nslaves;
++	uint32_t qos_freq; /* QOS Clock in KHz */
++	uint32_t qos_baseoffset;
++	uint32_t qos_delta;
++	uint32_t *mas_modes;
++	struct msm_bus_noc_commit cdata[NUM_CTX];
++};
++
++struct msm_bus_noc_qos_priority {
++	uint32_t high_prio;
++	uint32_t low_prio;
++	uint32_t read_prio;
++	uint32_t write_prio;
++	uint32_t p1;
++	uint32_t p0;
++};
++
++struct msm_bus_noc_qos_bw {
++	uint64_t bw; /* Bandwidth in bytes per second */
++	uint32_t ws; /* Window size in nano seconds */
++};
++
++void msm_bus_noc_init(struct msm_bus_noc_info *ninfo);
++uint8_t msm_bus_noc_get_qos_mode(void __iomem *base, uint32_t qos_off,
++	uint32_t mport, uint32_t qos_delta, uint32_t mode, uint32_t perm_mode);
++void msm_bus_noc_get_qos_priority(void __iomem *base, uint32_t qos_off,
++	uint32_t mport, uint32_t qos_delta,
++	struct msm_bus_noc_qos_priority *qprio);
++void msm_bus_noc_get_qos_bw(void __iomem *base, uint32_t qos_off,
++	uint32_t qos_freq, uint32_t mport, uint32_t qos_delta,
++	uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw);
++#endif /*_ARCH_ARM_MACH_MSM_BUS_NOC_H */
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_of.c
+@@ -0,0 +1,705 @@
++/* Copyright (c) 2012-2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
++
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "msm-bus.h"
++#include "msm-bus-board.h"
++#include "msm_bus_core.h"
++
++static const char * const hw_sel_name[] = {"RPM", "NoC", "BIMC", NULL};
++static const char * const mode_sel_name[] = {"Fixed", "Limiter", "Bypass",
++						"Regulator", NULL};
++
++static int get_num(const char *const str[], const char *name)
++{
++	int i = 0;
++
++	do {
++		if (!strcmp(name, str[i]))
++			return i;
++
++		i++;
++	} while (str[i] != NULL);
++
++	pr_err("Error: string %s not found\n", name);
++	return -EINVAL;
++}
++
++#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_MSM_BUS_SCALING)
++static struct msm_bus_scale_pdata *get_pdata(struct platform_device *pdev,
++	struct device_node *of_node)
++{
++	struct msm_bus_scale_pdata *pdata = NULL;
++	struct msm_bus_paths *usecase = NULL;
++	int i = 0, j, ret, num_usecases = 0, num_paths, len;
++	const uint32_t *vec_arr = NULL;
++	bool mem_err = false;
++
++	if (!pdev) {
++		pr_err("Error: Null Platform device\n");
++		return NULL;
++	}
++
++	pdata = devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_scale_pdata),
++		GFP_KERNEL);
++	if (!pdata) {
++		pr_err("Error: Memory allocation for pdata failed\n");
++		mem_err = true;
++		goto err;
++	}
++
++	ret = of_property_read_string(of_node, "qcom,msm-bus,name",
++		&pdata->name);
++	if (ret) {
++		pr_err("Error: Client name not found\n");
++		goto err;
++	}
++
++	ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
++		&num_usecases);
++	if (ret) {
++		pr_err("Error: num-usecases not found\n");
++		goto err;
++	}
++
++	pdata->num_usecases = num_usecases;
++
++	if (of_property_read_bool(of_node, "qcom,msm-bus,active-only"))
++		pdata->active_only = 1;
++	else {
++		pr_debug("active_only flag absent.\n");
++		pr_debug("Using dual context by default\n");
++	}
++
++	usecase = devm_kzalloc(&pdev->dev, (sizeof(struct msm_bus_paths) *
++		pdata->num_usecases), GFP_KERNEL);
++	if (!usecase) {
++		pr_err("Error: Memory allocation for paths failed\n");
++		mem_err = true;
++		goto err;
++	}
++
++	ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
++		&num_paths);
++	if (ret) {
++		pr_err("Error: num_paths not found\n");
++		goto err;
++	}
++
++	vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
++	if (vec_arr == NULL) {
++		pr_err("Error: Vector array not found\n");
++		goto err;
++	}
++
++	if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
++		pr_err("Error: Length-error on getting vectors\n");
++		goto err;
++	}
++
++	for (i = 0; i < num_usecases; i++) {
++		usecase[i].num_paths = num_paths;
++		usecase[i].vectors = devm_kzalloc(&pdev->dev, num_paths *
++			sizeof(struct msm_bus_vectors), GFP_KERNEL);
++		if (!usecase[i].vectors) {
++			mem_err = true;
++			pr_err("Error: Mem alloc failure in vectors\n");
++			goto err;
++		}
++
++		for (j = 0; j < num_paths; j++) {
++			int index = ((i * num_paths) + j) * 4;
++			usecase[i].vectors[j].src = be32_to_cpu(vec_arr[index]);
++			usecase[i].vectors[j].dst =
++				be32_to_cpu(vec_arr[index + 1]);
++			usecase[i].vectors[j].ab = (uint64_t)
++				KBTOB(be32_to_cpu(vec_arr[index + 2]));
++			usecase[i].vectors[j].ib = (uint64_t)
++				KBTOB(be32_to_cpu(vec_arr[index + 3]));
++		}
++	}
++
++	pdata->usecase = usecase;
++	return pdata;
++err:
++	if (mem_err) {
++		for (; i > 0; i--)
++			kfree(usecase[i-1].vectors);
++
++		kfree(usecase);
++		kfree(pdata);
++	}
++
++	return NULL;
++}
++
++/**
++ * msm_bus_cl_get_pdata() - Generate bus client data from device tree
++ * provided by clients.
++ *
++ * of_node: Device tree node to extract information from
++ *
++ * The function returns a valid pointer to the allocated bus-scale-pdata
++ * if the vectors were correctly read from the client's device node.
++ * Any error in reading or parsing the device node will return NULL
++ * to the caller.
++ */
++struct msm_bus_scale_pdata *msm_bus_cl_get_pdata(struct platform_device *pdev)
++{
++	struct device_node *of_node;
++	struct msm_bus_scale_pdata *pdata = NULL;
++
++	if (!pdev) {
++		pr_err("Error: Null Platform device\n");
++		return NULL;
++	}
++
++	of_node = pdev->dev.of_node;
++	pdata = get_pdata(pdev, of_node);
++	if (!pdata) {
++		pr_err("client has to provide missing entry for successful registration\n");
++		return NULL;
++	}
++
++	return pdata;
++}
++EXPORT_SYMBOL(msm_bus_cl_get_pdata);
++
++/**
++ * msm_bus_cl_pdata_from_node() - Generate bus client data from device tree
++ * node provided by clients. This function should be used when a client
++ * driver needs to register multiple bus-clients from a single device-tree
++ * node associated with the platform-device.
++ *
++ * of_node: The subnode containing information about the bus scaling
++ * data
++ *
++ * pdev: Platform device associated with the device-tree node
++ *
++ * The function returns a valid pointer to the allocated bus-scale-pdata
++ * if the vectors were correctly read from the client's device node.
++ * Any error in reading or parsing the device node will return NULL
++ * to the caller.
++ */
++struct msm_bus_scale_pdata *msm_bus_pdata_from_node(
++		struct platform_device *pdev, struct device_node *of_node)
++{
++	struct msm_bus_scale_pdata *pdata = NULL;
++
++	if (!pdev) {
++		pr_err("Error: Null Platform device\n");
++		return NULL;
++	}
++
++	if (!of_node) {
++		pr_err("Error: Null of_node passed to bus driver\n");
++		return NULL;
++	}
++
++	pdata = get_pdata(pdev, of_node);
++	if (!pdata) {
++		pr_err("client has to provide missing entry for successful registration\n");
++		return NULL;
++	}
++
++	return pdata;
++}
++EXPORT_SYMBOL(msm_bus_pdata_from_node);
++
++/**
++ * msm_bus_cl_clear_pdata() - Clear pdata allocated from device-tree
++ * of_node: Device tree node to extract information from
++ */
++void msm_bus_cl_clear_pdata(struct msm_bus_scale_pdata *pdata)
++{
++	int i;
++
++	for (i = 0; i < pdata->num_usecases; i++)
++		kfree(pdata->usecase[i].vectors);
++
++	kfree(pdata->usecase);
++	kfree(pdata);
++}
++EXPORT_SYMBOL(msm_bus_cl_clear_pdata);
++#endif
++
++static int *get_arr(struct platform_device *pdev,
++		const struct device_node *node, const char *prop,
++		int *nports)
++{
++	int size = 0, ret;
++	int *arr = NULL;
++
++	if (of_get_property(node, prop, &size)) {
++		*nports = size / sizeof(int);
++	} else {
++		pr_debug("Property %s not available\n", prop);
++		*nports = 0;
++		return NULL;
++	}
++
++	if (!size) {
++		*nports = 0;
++		return NULL;
++	}
++
++	arr = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
++	if (ZERO_OR_NULL_PTR(arr)) {
++		pr_err("Error: Failed to alloc mem for %s\n", prop);
++		return NULL;
++	}
++
++	ret = of_property_read_u32_array(node, prop, (u32 *)arr, *nports);
++	if (ret) {
++		pr_err("Error in reading property: %s\n", prop);
++		goto err;
++	}
++
++	return arr;
++err:
++	devm_kfree(&pdev->dev, arr);
++	return NULL;
++}
++
++static u64 *get_th_params(struct platform_device *pdev,
++		const struct device_node *node, const char *prop,
++		int *nports)
++{
++	int size = 0, ret;
++	u64 *ret_arr = NULL;
++	int *arr = NULL;
++	int i;
++
++	if (of_get_property(node, prop, &size)) {
++		*nports = size / sizeof(int);
++	} else {
++		pr_debug("Property %s not available\n", prop);
++		*nports = 0;
++		return NULL;
++	}
++
++	if (!size) {
++		*nports = 0;
++		return NULL;
++	}
++
++	ret_arr = devm_kzalloc(&pdev->dev, (*nports * sizeof(u64)),
++							GFP_KERNEL);
++	if (ZERO_OR_NULL_PTR(ret_arr)) {
++		pr_err("Error: Failed to alloc mem for ret arr %s\n", prop);
++		return NULL;
++	}
++
++	arr = kzalloc(size, GFP_KERNEL);
++	if ((ZERO_OR_NULL_PTR(arr))) {
++		pr_err("Error: Failed to alloc temp mem for %s\n", prop);
++		return NULL;
++	}
++
++	ret = of_property_read_u32_array(node, prop, (u32 *)arr, *nports);
++	if (ret) {
++		pr_err("Error in reading property: %s\n", prop);
++		goto err;
++	}
++
++	for (i = 0; i < *nports; i++)
++		ret_arr[i] = (uint64_t)KBTOB(arr[i]);
++
++	MSM_BUS_DBG("%s: num entries %d prop %s", __func__, *nports, prop);
++
++	for (i = 0; i < *nports; i++)
++		MSM_BUS_DBG("Th %d val %llu", i, ret_arr[i]);
++
++	kfree(arr);
++	return ret_arr;
++err:
++	kfree(arr);
++	devm_kfree(&pdev->dev, ret_arr);
++	return NULL;
++}
++
++static struct msm_bus_node_info *get_nodes(struct device_node *of_node,
++	struct platform_device *pdev,
++	struct msm_bus_fabric_registration *pdata)
++{
++	struct msm_bus_node_info *info;
++	struct device_node *child_node = NULL;
++	int i = 0, ret;
++	int num_bw = 0;
++	u32 temp;
++
++	for_each_child_of_node(of_node, child_node) {
++		i++;
++	}
++
++	pdata->len = i;
++	info = (struct msm_bus_node_info *)
++		devm_kzalloc(&pdev->dev, sizeof(struct msm_bus_node_info) *
++			pdata->len, GFP_KERNEL);
++	if (ZERO_OR_NULL_PTR(info)) {
++		pr_err("Failed to alloc memory for nodes: %d\n", pdata->len);
++		goto err;
++	}
++
++	i = 0;
++	child_node = NULL;
++	for_each_child_of_node(of_node, child_node) {
++		const char *sel_str;
++
++		ret = of_property_read_string(child_node, "label",
++			&info[i].name);
++		if (ret)
++			pr_err("Error reading node label\n");
++
++		ret = of_property_read_u32(child_node, "cell-id", &info[i].id);
++		if (ret) {
++			pr_err("Error reading node id\n");
++			goto err;
++		}
++
++		if (of_property_read_bool(child_node, "qcom,gateway"))
++			info[i].gateway = 1;
++
++		of_property_read_u32(child_node, "qcom,mas-hw-id",
++			&info[i].mas_hw_id);
++
++		of_property_read_u32(child_node, "qcom,slv-hw-id",
++			&info[i].slv_hw_id);
++		info[i].masterp = get_arr(pdev, child_node,
++					"qcom,masterp", &info[i].num_mports);
++		/* No need to store number of qports */
++		info[i].qport = get_arr(pdev, child_node,
++					"qcom,qport", &ret);
++		pdata->nmasters += info[i].num_mports;
++
++
++		info[i].slavep = get_arr(pdev, child_node,
++					"qcom,slavep", &info[i].num_sports);
++		pdata->nslaves += info[i].num_sports;
++
++
++		info[i].tier = get_arr(pdev, child_node,
++					"qcom,tier", &info[i].num_tiers);
++
++		if (of_property_read_bool(child_node, "qcom,ahb"))
++			info[i].ahb = 1;
++
++		ret = of_property_read_string(child_node, "qcom,hw-sel",
++			&sel_str);
++		if (ret)
++			info[i].hw_sel = 0;
++		else {
++			ret =  get_num(hw_sel_name, sel_str);
++			if (ret < 0) {
++				pr_err("Invalid hw-sel\n");
++				goto err;
++			}
++
++			info[i].hw_sel = ret;
++		}
++
++		of_property_read_u32(child_node, "qcom,buswidth",
++			&info[i].buswidth);
++		of_property_read_u32(child_node, "qcom,ws", &info[i].ws);
++
++		info[i].dual_conf =
++			of_property_read_bool(child_node, "qcom,dual-conf");
++
++
++		info[i].th = get_th_params(pdev, child_node, "qcom,thresh",
++						&info[i].num_thresh);
++
++		info[i].bimc_bw = get_th_params(pdev, child_node,
++						"qcom,bimc,bw", &num_bw);
++
++		if (num_bw != info[i].num_thresh) {
++			pr_err("%s:num_bw %d must equal num_thresh %d",
++				__func__, num_bw, info[i].num_thresh);
++			pr_err("%s:Err setting up dual conf for %s",
++				__func__, info[i].name);
++			goto err;
++		}
++
++		of_property_read_u32(child_node, "qcom,bimc,gp",
++			&info[i].bimc_gp);
++		of_property_read_u32(child_node, "qcom,bimc,thmp",
++			&info[i].bimc_thmp);
++
++		ret = of_property_read_string(child_node, "qcom,mode-thresh",
++			&sel_str);
++		if (ret)
++			info[i].mode_thresh = 0;
++		else {
++			ret = get_num(mode_sel_name, sel_str);
++			if (ret < 0) {
++				pr_err("Unknown mode :%s\n", sel_str);
++				goto err;
++			}
++
++			info[i].mode_thresh = ret;
++			MSM_BUS_DBG("AXI: THreshold mode set: %d\n",
++					info[i].mode_thresh);
++		}
++
++		ret = of_property_read_string(child_node, "qcom,mode",
++				&sel_str);
++
++		if (ret)
++			info[i].mode = 0;
++		else {
++			ret = get_num(mode_sel_name, sel_str);
++			if (ret < 0) {
++				pr_err("Unknown mode :%s\n", sel_str);
++				goto err;
++			}
++
++			info[i].mode = ret;
++		}
++
++		info[i].nr_lim =
++			of_property_read_bool(child_node, "qcom,nr-lim");
++
++		ret = of_property_read_u32(child_node, "qcom,ff",
++							&info[i].ff);
++		if (ret) {
++			pr_debug("fudge factor not present %d", info[i].id);
++			info[i].ff = 0;
++		}
++
++		ret = of_property_read_u32(child_node, "qcom,floor-bw",
++						&temp);
++		if (ret) {
++			pr_debug("fabdev floor bw not present %d", info[i].id);
++			info[i].floor_bw = 0;
++		} else {
++			info[i].floor_bw = KBTOB(temp);
++		}
++
++		info[i].rt_mas =
++			of_property_read_bool(child_node, "qcom,rt-mas");
++
++		ret = of_property_read_string(child_node, "qcom,perm-mode",
++			&sel_str);
++		if (ret)
++			info[i].perm_mode = 0;
++		else {
++			ret = get_num(mode_sel_name, sel_str);
++			if (ret < 0)
++				goto err;
++
++			info[i].perm_mode = 1 << ret;
++		}
++
++		of_property_read_u32(child_node, "qcom,prio-lvl",
++			&info[i].prio_lvl);
++		of_property_read_u32(child_node, "qcom,prio-rd",
++			&info[i].prio_rd);
++		of_property_read_u32(child_node, "qcom,prio-wr",
++			&info[i].prio_wr);
++		of_property_read_u32(child_node, "qcom,prio0", &info[i].prio0);
++		of_property_read_u32(child_node, "qcom,prio1", &info[i].prio1);
++		ret = of_property_read_string(child_node, "qcom,slaveclk-dual",
++			&info[i].slaveclk[DUAL_CTX]);
++		if (!ret)
++			pr_debug("Got slaveclk_dual: %s\n",
++				info[i].slaveclk[DUAL_CTX]);
++		else
++			info[i].slaveclk[DUAL_CTX] = NULL;
++
++		ret = of_property_read_string(child_node,
++			"qcom,slaveclk-active", &info[i].slaveclk[ACTIVE_CTX]);
++		if (!ret)
++			pr_debug("Got slaveclk_active\n");
++		else
++			info[i].slaveclk[ACTIVE_CTX] = NULL;
++
++		ret = of_property_read_string(child_node, "qcom,memclk-dual",
++			&info[i].memclk[DUAL_CTX]);
++		if (!ret)
++			pr_debug("Got memclk_dual\n");
++		else
++			info[i].memclk[DUAL_CTX] = NULL;
++
++		ret = of_property_read_string(child_node, "qcom,memclk-active",
++			&info[i].memclk[ACTIVE_CTX]);
++		if (!ret)
++			pr_debug("Got memclk_active\n");
++		else
++			info[i].memclk[ACTIVE_CTX] = NULL;
++
++		ret = of_property_read_string(child_node, "qcom,iface-clk-node",
++			&info[i].iface_clk_node);
++		if (!ret)
++			pr_debug("Got iface_clk_node\n");
++		else
++			info[i].iface_clk_node = NULL;
++
++		pr_debug("Node name: %s\n", info[i].name);
++		of_node_put(child_node);
++		i++;
++	}
++
++	pr_debug("Bus %d added: %d masters\n", pdata->id, pdata->nmasters);
++	pr_debug("Bus %d added: %d slaves\n", pdata->id, pdata->nslaves);
++	return info;
++err:
++	return NULL;
++}
++
++void msm_bus_of_get_nfab(struct platform_device *pdev,
++		struct msm_bus_fabric_registration *pdata)
++{
++	struct device_node *of_node;
++	int ret, nfab = 0;
++
++	if (!pdev) {
++		pr_err("Error: Null platform device\n");
++		return;
++	}
++
++	of_node = pdev->dev.of_node;
++	ret = of_property_read_u32(of_node, "qcom,nfab",
++		&nfab);
++	if (!ret)
++		pr_debug("Fab_of: Read number of buses: %u\n", nfab);
++
++	msm_bus_board_set_nfab(pdata, nfab);
++}
++
++struct msm_bus_fabric_registration
++	*msm_bus_of_get_fab_data(struct platform_device *pdev)
++{
++	struct device_node *of_node;
++	struct msm_bus_fabric_registration *pdata;
++	bool mem_err = false;
++	int ret = 0;
++	const char *sel_str;
++	u32 temp;
++
++	if (!pdev) {
++		pr_err("Error: Null platform device\n");
++		return NULL;
++	}
++
++	of_node = pdev->dev.of_node;
++	pdata = devm_kzalloc(&pdev->dev,
++			sizeof(struct msm_bus_fabric_registration), GFP_KERNEL);
++	if (!pdata) {
++		pr_err("Error: Memory allocation for pdata failed\n");
++		mem_err = true;
++		goto err;
++	}
++
++	ret = of_property_read_string(of_node, "label", &pdata->name);
++	if (ret) {
++		pr_err("Error: label not found\n");
++		goto err;
++	}
++	pr_debug("Fab_of: Read name: %s\n", pdata->name);
++
++	ret = of_property_read_u32(of_node, "cell-id",
++		&pdata->id);
++	if (ret) {
++		pr_err("Error: num-usecases not found\n");
++		goto err;
++	}
++	pr_debug("Fab_of: Read id: %u\n", pdata->id);
++
++	if (of_property_read_bool(of_node, "qcom,ahb"))
++		pdata->ahb = 1;
++
++	ret = of_property_read_string(of_node, "qcom,fabclk-dual",
++		&pdata->fabclk[DUAL_CTX]);
++	if (ret) {
++		pr_debug("fabclk_dual not available\n");
++		pdata->fabclk[DUAL_CTX] = NULL;
++	} else
++		pr_debug("Fab_of: Read clk dual ctx: %s\n",
++			pdata->fabclk[DUAL_CTX]);
++	ret = of_property_read_string(of_node, "qcom,fabclk-active",
++		&pdata->fabclk[ACTIVE_CTX]);
++	if (ret) {
++		pr_debug("Error: fabclk_active not available\n");
++		pdata->fabclk[ACTIVE_CTX] = NULL;
++	} else
++		pr_debug("Fab_of: Read clk act ctx: %s\n",
++			pdata->fabclk[ACTIVE_CTX]);
++
++	ret = of_property_read_u32(of_node, "qcom,ntieredslaves",
++		&pdata->ntieredslaves);
++	if (ret) {
++		pr_err("Error: ntieredslaves not found\n");
++		goto err;
++	}
++
++	ret = of_property_read_u32(of_node, "qcom,qos-freq", &pdata->qos_freq);
++	if (ret)
++		pr_debug("qos_freq not available\n");
++
++	ret = of_property_read_string(of_node, "qcom,hw-sel", &sel_str);
++	if (ret) {
++		pr_err("Error: hw_sel not found\n");
++		goto err;
++	} else {
++		ret = get_num(hw_sel_name, sel_str);
++		if (ret < 0)
++			goto err;
++
++		pdata->hw_sel = ret;
++	}
++
++	if (of_property_read_bool(of_node, "qcom,virt"))
++		pdata->virt = true;
++
++	ret = of_property_read_u32(of_node, "qcom,qos-baseoffset",
++						&pdata->qos_baseoffset);
++	if (ret)
++		pr_debug("%s:qos_baseoffset not available\n", __func__);
++
++	ret = of_property_read_u32(of_node, "qcom,qos-delta",
++						&pdata->qos_delta);
++	if (ret)
++		pr_debug("%s:qos_delta not available\n", __func__);
++
++	if (of_property_read_bool(of_node, "qcom,rpm-en"))
++		pdata->rpm_enabled = 1;
++
++	ret = of_property_read_u32(of_node, "qcom,nr-lim-thresh",
++						&temp);
++
++	if (ret) {
++		pr_err("nr-lim threshold not specified");
++		pdata->nr_lim_thresh = 0;
++	} else {
++		pdata->nr_lim_thresh = KBTOB(temp);
++	}
++
++	ret = of_property_read_u32(of_node, "qcom,eff-fact",
++						&pdata->eff_fact);
++	if (ret) {
++		pr_err("Fab eff-factor not present");
++		pdata->eff_fact = 0;
++	}
++
++	pdata->info = get_nodes(of_node, pdev, pdata);
++	return pdata;
++err:
++	return NULL;
++}
++EXPORT_SYMBOL(msm_bus_of_get_fab_data);
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_of_adhoc.c
+@@ -0,0 +1,641 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
++
++#include <linux/clk.h>
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include "msm-bus.h"
++#include "msm-bus-board.h"
++#include "msm_bus_rules.h"
++#include "msm_bus_core.h"
++#include "msm_bus_adhoc.h"
++
++#define DEFAULT_QOS_FREQ	19200
++#define DEFAULT_UTIL_FACT	100
++#define DEFAULT_VRAIL_COMP	100
++
++static int get_qos_mode(struct platform_device *pdev,
++			struct device_node *node, const char *qos_mode)
++{
++	const char *qos_names[] = {"fixed", "limiter", "bypass", "regulator"};
++	int i = 0;
++	int ret = -1;
++
++	if (!qos_mode)
++		goto exit_get_qos_mode;
++
++	for (i = 0; i < ARRAY_SIZE(qos_names); i++) {
++		if (!strcmp(qos_mode, qos_names[i]))
++			break;
++	}
++	if (i == ARRAY_SIZE(qos_names))
++		dev_err(&pdev->dev, "Cannot match mode qos %s using Bypass",
++				qos_mode);
++	else
++		ret = i;
++
++exit_get_qos_mode:
++	return ret;
++}
++
++static int *get_arr(struct platform_device *pdev,
++		struct device_node *node, const char *prop,
++		int *nports)
++{
++	int size = 0, ret;
++	int *arr = NULL;
++
++	if (of_get_property(node, prop, &size)) {
++		*nports = size / sizeof(int);
++	} else {
++		dev_dbg(&pdev->dev, "Property %s not available\n", prop);
++		*nports = 0;
++		return NULL;
++	}
++
++	arr = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
++	if ((size > 0) && ZERO_OR_NULL_PTR(arr)) {
++		dev_err(&pdev->dev, "Error: Failed to alloc mem for %s\n",
++				prop);
++		return NULL;
++	}
++
++	ret = of_property_read_u32_array(node, prop, (u32 *)arr, *nports);
++	if (ret) {
++		dev_err(&pdev->dev, "Error in reading property: %s\n", prop);
++		goto arr_err;
++	}
++
++	return arr;
++arr_err:
++	devm_kfree(&pdev->dev, arr);
++	return NULL;
++}
++
++static struct msm_bus_fab_device_type *get_fab_device_info(
++		struct device_node *dev_node,
++		struct platform_device *pdev)
++{
++	struct msm_bus_fab_device_type *fab_dev;
++	unsigned int ret;
++	struct resource *res;
++	const char *base_name;
++
++	fab_dev = devm_kzalloc(&pdev->dev,
++			sizeof(struct msm_bus_fab_device_type),
++			GFP_KERNEL);
++	if (!fab_dev) {
++		dev_err(&pdev->dev,
++			"Error: Unable to allocate memory for fab_dev\n");
++		return NULL;
++	}
++
++	ret = of_property_read_string(dev_node, "qcom,base-name", &base_name);
++	if (ret) {
++		dev_err(&pdev->dev, "Error: Unable to get base address name\n");
++		goto fab_dev_err;
++	}
++
++	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, base_name);
++	if (!res) {
++		dev_err(&pdev->dev, "Error getting qos base addr %s\n",
++								base_name);
++		goto fab_dev_err;
++	}
++	fab_dev->pqos_base = res->start;
++	fab_dev->qos_range = resource_size(res);
++	fab_dev->bypass_qos_prg = of_property_read_bool(dev_node,
++						"qcom,bypass-qos-prg");
++
++	ret = of_property_read_u32(dev_node, "qcom,base-offset",
++			&fab_dev->base_offset);
++	if (ret)
++		dev_dbg(&pdev->dev, "Bus base offset is missing\n");
++
++	ret = of_property_read_u32(dev_node, "qcom,qos-off",
++			&fab_dev->qos_off);
++	if (ret)
++		dev_dbg(&pdev->dev, "Bus qos off is missing\n");
++
++
++	ret = of_property_read_u32(dev_node, "qcom,bus-type",
++						&fab_dev->bus_type);
++	if (ret) {
++		dev_warn(&pdev->dev, "Bus type is missing\n");
++		goto fab_dev_err;
++	}
++
++	ret = of_property_read_u32(dev_node, "qcom,qos-freq",
++						&fab_dev->qos_freq);
++	if (ret) {
++		dev_dbg(&pdev->dev, "Bus qos freq is missing\n");
++		fab_dev->qos_freq = DEFAULT_QOS_FREQ;
++	}
++
++	ret = of_property_read_u32(dev_node, "qcom,util-fact",
++						&fab_dev->util_fact);
++	if (ret) {
++		dev_info(&pdev->dev, "Util-fact is missing, default to %d\n",
++				DEFAULT_UTIL_FACT);
++		fab_dev->util_fact = DEFAULT_UTIL_FACT;
++	}
++
++	ret = of_property_read_u32(dev_node, "qcom,vrail-comp",
++						&fab_dev->vrail_comp);
++	if (ret) {
++		dev_info(&pdev->dev, "Vrail-comp is missing, default to %d\n",
++				DEFAULT_VRAIL_COMP);
++		fab_dev->vrail_comp = DEFAULT_VRAIL_COMP;
++	}
++
++	return fab_dev;
++
++fab_dev_err:
++	devm_kfree(&pdev->dev, fab_dev);
++	fab_dev = 0;
++	return NULL;
++}
++
++static void get_qos_params(
++		struct device_node * const dev_node,
++		struct platform_device * const pdev,
++		struct msm_bus_node_info_type *node_info)
++{
++	const char *qos_mode = NULL;
++	unsigned int ret;
++	unsigned int temp;
++
++	ret = of_property_read_string(dev_node, "qcom,qos-mode", &qos_mode);
++
++	if (ret)
++		node_info->qos_params.mode = -1;
++	else
++		node_info->qos_params.mode = get_qos_mode(pdev, dev_node,
++								qos_mode);
++
++	of_property_read_u32(dev_node, "qcom,prio-lvl",
++					&node_info->qos_params.prio_lvl);
++
++	of_property_read_u32(dev_node, "qcom,prio1",
++						&node_info->qos_params.prio1);
++
++	of_property_read_u32(dev_node, "qcom,prio0",
++						&node_info->qos_params.prio0);
++
++	of_property_read_u32(dev_node, "qcom,prio-rd",
++					&node_info->qos_params.prio_rd);
++
++	of_property_read_u32(dev_node, "qcom,prio-wr",
++						&node_info->qos_params.prio_wr);
++
++	of_property_read_u32(dev_node, "qcom,gp",
++						&node_info->qos_params.gp);
++
++	of_property_read_u32(dev_node, "qcom,thmp",
++						&node_info->qos_params.thmp);
++
++	of_property_read_u32(dev_node, "qcom,ws",
++						&node_info->qos_params.ws);
++
++	ret = of_property_read_u32(dev_node, "qcom,bw_buffer", &temp);
++
++	if (ret)
++		node_info->qos_params.bw_buffer = 0;
++	else
++		node_info->qos_params.bw_buffer = KBTOB(temp);
++
++}
++
++
++static struct msm_bus_node_info_type *get_node_info_data(
++		struct device_node * const dev_node,
++		struct platform_device * const pdev)
++{
++	struct msm_bus_node_info_type *node_info;
++	unsigned int ret;
++	int size;
++	int i;
++	struct device_node *con_node;
++	struct device_node *bus_dev;
++
++	node_info = devm_kzalloc(&pdev->dev,
++			sizeof(struct msm_bus_node_info_type),
++			GFP_KERNEL);
++	if (!node_info) {
++		dev_err(&pdev->dev,
++			"Error: Unable to allocate memory for node_info\n");
++		return NULL;
++	}
++
++	ret = of_property_read_u32(dev_node, "cell-id", &node_info->id);
++	if (ret) {
++		dev_warn(&pdev->dev, "Bus node is missing cell-id\n");
++		goto node_info_err;
++	}
++	ret = of_property_read_string(dev_node, "label", &node_info->name);
++	if (ret) {
++		dev_warn(&pdev->dev, "Bus node is missing name\n");
++		goto node_info_err;
++	}
++	node_info->qport = get_arr(pdev, dev_node, "qcom,qport",
++			&node_info->num_qports);
++
++	if (of_get_property(dev_node, "qcom,connections", &size)) {
++		node_info->num_connections = size / sizeof(int);
++		node_info->connections = devm_kzalloc(&pdev->dev, size,
++				GFP_KERNEL);
++	} else {
++		node_info->num_connections = 0;
++		node_info->connections = 0;
++	}
++
++	for (i = 0; i < node_info->num_connections; i++) {
++		con_node = of_parse_phandle(dev_node, "qcom,connections", i);
++		if (IS_ERR_OR_NULL(con_node))
++			goto node_info_err;
++
++		if (of_property_read_u32(con_node, "cell-id",
++				&node_info->connections[i]))
++			goto node_info_err;
++		of_node_put(con_node);
++	}
++
++	if (of_get_property(dev_node, "qcom,blacklist", &size)) {
++		node_info->num_blist = size/sizeof(u32);
++		node_info->black_listed_connections = devm_kzalloc(&pdev->dev,
++		size, GFP_KERNEL);
++	} else {
++		node_info->num_blist = 0;
++		node_info->black_listed_connections = 0;
++	}
++
++	for (i = 0; i < node_info->num_blist; i++) {
++		con_node = of_parse_phandle(dev_node, "qcom,blacklist", i);
++		if (IS_ERR_OR_NULL(con_node))
++			goto node_info_err;
++
++		if (of_property_read_u32(con_node, "cell-id",
++				&node_info->black_listed_connections[i]))
++			goto node_info_err;
++		of_node_put(con_node);
++	}
++
++	bus_dev = of_parse_phandle(dev_node, "qcom,bus-dev", 0);
++	if (!IS_ERR_OR_NULL(bus_dev)) {
++		if (of_property_read_u32(bus_dev, "cell-id",
++			&node_info->bus_device_id)) {
++			dev_err(&pdev->dev, "Can't find bus device. Node %d",
++					node_info->id);
++			goto node_info_err;
++		}
++
++		of_node_put(bus_dev);
++	} else
++		dev_dbg(&pdev->dev, "Can't find bdev phandle for %d",
++					node_info->id);
++
++	node_info->is_fab_dev = of_property_read_bool(dev_node, "qcom,fab-dev");
++	node_info->virt_dev = of_property_read_bool(dev_node, "qcom,virt-dev");
++
++	ret = of_property_read_u32(dev_node, "qcom,buswidth",
++						&node_info->buswidth);
++	if (ret) {
++		dev_dbg(&pdev->dev, "Using default 8 bytes %d", node_info->id);
++		node_info->buswidth = 8;
++	}
++
++	ret = of_property_read_u32(dev_node, "qcom,mas-rpm-id",
++						&node_info->mas_rpm_id);
++	if (ret) {
++		dev_dbg(&pdev->dev, "mas rpm id is missing\n");
++		node_info->mas_rpm_id = -1;
++	}
++
++	ret = of_property_read_u32(dev_node, "qcom,slv-rpm-id",
++						&node_info->slv_rpm_id);
++	if (ret) {
++		dev_dbg(&pdev->dev, "slv rpm id is missing\n");
++		node_info->slv_rpm_id = -1;
++	}
++	ret = of_property_read_u32(dev_node, "qcom,util-fact",
++						&node_info->util_fact);
++	if (ret)
++		node_info->util_fact = 0;
++	ret = of_property_read_u32(dev_node, "qcom,vrail-comp",
++						&node_info->vrail_comp);
++	if (ret)
++		node_info->vrail_comp = 0;
++	get_qos_params(dev_node, pdev, node_info);
++
++	return node_info;
++
++node_info_err:
++	devm_kfree(&pdev->dev, node_info);
++	node_info = 0;
++	return NULL;
++}
++
++static unsigned int get_bus_node_device_data(
++		struct device_node * const dev_node,
++		struct platform_device * const pdev,
++		struct msm_bus_node_device_type * const node_device)
++{
++	node_device->node_info = get_node_info_data(dev_node, pdev);
++	if (IS_ERR_OR_NULL(node_device->node_info)) {
++		dev_err(&pdev->dev, "Error: Node info missing\n");
++		return -ENODATA;
++	}
++	node_device->ap_owned = of_property_read_bool(dev_node,
++							"qcom,ap-owned");
++
++	if (node_device->node_info->is_fab_dev) {
++		dev_dbg(&pdev->dev, "Dev %d\n", node_device->node_info->id);
++
++		if (!node_device->node_info->virt_dev) {
++			node_device->fabdev =
++				get_fab_device_info(dev_node, pdev);
++			if (IS_ERR_OR_NULL(node_device->fabdev)) {
++				dev_err(&pdev->dev,
++					"Error: Fabric device info missing\n");
++				devm_kfree(&pdev->dev, node_device->node_info);
++				return -ENODATA;
++			}
++		}
++		node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node,
++							"bus_clk");
++
++		if (IS_ERR_OR_NULL(node_device->clk[DUAL_CTX].clk))
++			dev_dbg(&pdev->dev,
++				"%s:Failed to get bus clk for bus%d ctx%d",
++				__func__, node_device->node_info->id,
++								DUAL_CTX);
++
++		node_device->clk[ACTIVE_CTX].clk = of_clk_get_by_name(dev_node,
++							"bus_a_clk");
++		if (IS_ERR_OR_NULL(node_device->clk[ACTIVE_CTX].clk))
++			dev_err(&pdev->dev,
++				"Failed to get bus clk for bus%d ctx%d",
++				 node_device->node_info->id, ACTIVE_CTX);
++		if (msmbus_coresight_init_adhoc(pdev, dev_node))
++			dev_warn(&pdev->dev,
++				 "Coresight support absent for bus: %d\n",
++				  node_device->node_info->id);
++	} else {
++		node_device->qos_clk.clk = of_clk_get_by_name(dev_node,
++							"bus_qos_clk");
++
++		if (IS_ERR_OR_NULL(node_device->qos_clk.clk))
++			dev_dbg(&pdev->dev,
++				"%s:Failed to get bus qos clk for mas%d",
++				__func__, node_device->node_info->id);
++
++		node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node,
++							"node_clk");
++
++		if (IS_ERR_OR_NULL(node_device->clk[DUAL_CTX].clk))
++			dev_dbg(&pdev->dev,
++				"%s:Failed to get bus clk for bus%d ctx%d",
++				__func__, node_device->node_info->id,
++								DUAL_CTX);
++
++	}
++	return 0;
++}
++
++struct msm_bus_device_node_registration
++	*msm_bus_of_to_pdata(struct platform_device *pdev)
++{
++	struct device_node *of_node, *child_node;
++	struct msm_bus_device_node_registration *pdata;
++	unsigned int i = 0, j;
++	unsigned int ret;
++
++	if (!pdev) {
++		pr_err("Error: Null platform device\n");
++		return NULL;
++	}
++
++	of_node = pdev->dev.of_node;
++
++	pdata = devm_kzalloc(&pdev->dev,
++			sizeof(struct msm_bus_device_node_registration),
++			GFP_KERNEL);
++	if (!pdata) {
++		dev_err(&pdev->dev,
++				"Error: Memory allocation for pdata failed\n");
++		return NULL;
++	}
++
++	pdata->num_devices = of_get_child_count(of_node);
++
++	pdata->info = devm_kzalloc(&pdev->dev,
++			sizeof(struct msm_bus_node_device_type) *
++			pdata->num_devices, GFP_KERNEL);
++
++	if (!pdata->info) {
++		dev_err(&pdev->dev,
++			"Error: Memory allocation for pdata->info failed\n");
++		goto node_reg_err;
++	}
++
++	ret = 0;
++	for_each_child_of_node(of_node, child_node) {
++		ret = get_bus_node_device_data(child_node, pdev,
++				&pdata->info[i]);
++		if (ret) {
++			dev_err(&pdev->dev, "Error: unable to initialize bus nodes\n");
++			goto node_reg_err_1;
++		}
++		i++;
++	}
++
++	dev_dbg(&pdev->dev, "bus topology:\n");
++	for (i = 0; i < pdata->num_devices; i++) {
++		dev_dbg(&pdev->dev, "id %d\nnum_qports %d\nnum_connections %d",
++				pdata->info[i].node_info->id,
++				pdata->info[i].node_info->num_qports,
++				pdata->info[i].node_info->num_connections);
++		dev_dbg(&pdev->dev, "\nbus_device_id %d\n buswidth %d\n",
++				pdata->info[i].node_info->bus_device_id,
++				pdata->info[i].node_info->buswidth);
++		for (j = 0; j < pdata->info[i].node_info->num_connections;
++									j++) {
++			dev_dbg(&pdev->dev, "connection[%d]: %d\n", j,
++				pdata->info[i].node_info->connections[j]);
++		}
++		for (j = 0; j < pdata->info[i].node_info->num_blist;
++									 j++) {
++			dev_dbg(&pdev->dev, "black_listed_node[%d]: %d\n", j,
++				pdata->info[i].node_info->
++				black_listed_connections[j]);
++		}
++		if (pdata->info[i].fabdev)
++			dev_dbg(&pdev->dev, "base_addr %zu\nbus_type %d\n",
++					(size_t)pdata->info[i].
++						fabdev->pqos_base,
++					pdata->info[i].fabdev->bus_type);
++	}
++	return pdata;
++
++node_reg_err_1:
++	devm_kfree(&pdev->dev, pdata->info);
++node_reg_err:
++	devm_kfree(&pdev->dev, pdata);
++	pdata = NULL;
++	return NULL;
++}
++
++static int msm_bus_of_get_ids(struct platform_device *pdev,
++			struct device_node *dev_node, int **dev_ids,
++			int *num_ids, char *prop_name)
++{
++	int ret = 0;
++	int size, i;
++	struct device_node *rule_node;
++	int *ids = NULL;
++
++	if (of_get_property(dev_node, prop_name, &size)) {
++		*num_ids = size / sizeof(int);
++		ids = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
++	} else {
++		dev_err(&pdev->dev, "No rule nodes, skipping node");
++		ret = -ENXIO;
++		goto exit_get_ids;
++	}
++
++	*dev_ids = ids;
++	for (i = 0; i < *num_ids; i++) {
++		rule_node = of_parse_phandle(dev_node, prop_name, i);
++		if (IS_ERR_OR_NULL(rule_node)) {
++			dev_err(&pdev->dev, "Can't get rule node id");
++			ret = -ENXIO;
++			goto err_get_ids;
++		}
++
++		if (of_property_read_u32(rule_node, "cell-id",
++				&ids[i])) {
++			dev_err(&pdev->dev, "Can't get rule node id");
++			ret = -ENXIO;
++			goto err_get_ids;
++		}
++		of_node_put(rule_node);
++	}
++exit_get_ids:
++	return ret;
++err_get_ids:
++	devm_kfree(&pdev->dev, ids);
++	of_node_put(rule_node);
++	ids = NULL;
++	return ret;
++}
++
++int msm_bus_of_get_static_rules(struct platform_device *pdev,
++					struct bus_rule_type **static_rules)
++{
++	int ret = 0;
++	struct device_node *of_node, *child_node;
++	int num_rules = 0;
++	int rule_idx = 0;
++	int bw_fld = 0;
++	int i;
++	struct bus_rule_type *static_rule = NULL;
++
++	of_node = pdev->dev.of_node;
++	num_rules = of_get_child_count(of_node);
++	static_rule = devm_kzalloc(&pdev->dev,
++				sizeof(struct bus_rule_type) * num_rules,
++				GFP_KERNEL);
++
++	if (IS_ERR_OR_NULL(static_rule)) {
++		ret = -ENOMEM;
++		goto exit_static_rules;
++	}
++
++	*static_rules = static_rule;
++	for_each_child_of_node(of_node, child_node) {
++		ret = msm_bus_of_get_ids(pdev, child_node,
++			&static_rule[rule_idx].src_id,
++			&static_rule[rule_idx].num_src,
++			"qcom,src-nodes");
++
++		ret = msm_bus_of_get_ids(pdev, child_node,
++			&static_rule[rule_idx].dst_node,
++			&static_rule[rule_idx].num_dst,
++			"qcom,dest-node");
++
++		ret = of_property_read_u32(child_node, "qcom,src-field",
++				&static_rule[rule_idx].src_field);
++		if (ret) {
++			dev_err(&pdev->dev, "src-field missing");
++			ret = -ENXIO;
++			goto err_static_rules;
++		}
++
++		ret = of_property_read_u32(child_node, "qcom,src-op",
++				&static_rule[rule_idx].op);
++		if (ret) {
++			dev_err(&pdev->dev, "src-op missing");
++			ret = -ENXIO;
++			goto err_static_rules;
++		}
++
++		ret = of_property_read_u32(child_node, "qcom,mode",
++				&static_rule[rule_idx].mode);
++		if (ret) {
++			dev_err(&pdev->dev, "mode missing");
++			ret = -ENXIO;
++			goto err_static_rules;
++		}
++
++		ret = of_property_read_u32(child_node, "qcom,thresh", &bw_fld);
++		if (ret) {
++			dev_err(&pdev->dev, "thresh missing");
++			ret = -ENXIO;
++			goto err_static_rules;
++		} else
++			static_rule[rule_idx].thresh = KBTOB(bw_fld);
++
++		ret = of_property_read_u32(child_node, "qcom,dest-bw",
++								&bw_fld);
++		if (ret)
++			static_rule[rule_idx].dst_bw = 0;
++		else
++			static_rule[rule_idx].dst_bw = KBTOB(bw_fld);
++
++		rule_idx++;
++	}
++	ret = rule_idx;
++exit_static_rules:
++	return ret;
++err_static_rules:
++	for (i = 0; i < num_rules; i++) {
++		if (!IS_ERR_OR_NULL(static_rule)) {
++			if (!IS_ERR_OR_NULL(static_rule[i].src_id))
++				devm_kfree(&pdev->dev,
++						static_rule[i].src_id);
++			if (!IS_ERR_OR_NULL(static_rule[i].dst_node))
++				devm_kfree(&pdev->dev,
++						static_rule[i].dst_node);
++			devm_kfree(&pdev->dev, static_rule);
++		}
++	}
++	devm_kfree(&pdev->dev, *static_rules);
++	static_rules = NULL;
++	return ret;
++}
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_rules.c
+@@ -0,0 +1,624 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/list_sort.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include "msm-bus-board.h"
++#include "msm_bus_rules.h"
++#include <trace/events/trace_msm_bus.h>
++
++struct node_vote_info {
++	int id;
++	u64 ib;
++	u64 ab;
++	u64 clk;
++};
++
++struct rules_def {
++	int rule_id;
++	int num_src;
++	int state;
++	struct node_vote_info *src_info;
++	struct bus_rule_type rule_ops;
++	bool state_change;
++	struct list_head link;
++};
++
++struct rule_node_info {
++	int id;
++	void *data;
++	struct raw_notifier_head rule_notify_list;
++	int cur_rule;
++	int num_rules;
++	struct list_head node_rules;
++	struct list_head link;
++	struct rule_apply_rcm_info apply;
++};
++
++DEFINE_MUTEX(msm_bus_rules_lock);
++static LIST_HEAD(node_list);
++static struct rule_node_info *get_node(u32 id, void *data);
++
++#define LE(op1, op2)	(op1 <= op2)
++#define LT(op1, op2)	(op1 < op2)
++#define GE(op1, op2)	(op1 >= op2)
++#define GT(op1, op2)	(op1 > op2)
++#define NB_ID		(0x201)
++
++static struct rule_node_info *get_node(u32 id, void *data)
++{
++	struct rule_node_info *node_it = NULL;
++	struct rule_node_info *node_match = NULL;
++
++	list_for_each_entry(node_it, &node_list, link) {
++		if (node_it->id == id) {
++			if ((id == NB_ID)) {
++				if ((node_it->data == data)) {
++					node_match = node_it;
++					break;
++				}
++			} else {
++				node_match = node_it;
++				break;
++			}
++		}
++	}
++	return node_match;
++}
++
++static struct rule_node_info *gen_node(u32 id, void *data)
++{
++	struct rule_node_info *node_it = NULL;
++	struct rule_node_info *node_match = NULL;
++
++	list_for_each_entry(node_it, &node_list, link) {
++		if (node_it->id == id) {
++			node_match = node_it;
++			break;
++		}
++	}
++
++	if (!node_match) {
++		node_match = kzalloc(sizeof(struct rule_node_info), GFP_KERNEL);
++		if (!node_match) {
++			pr_err("%s: Cannot allocate memory", __func__);
++			goto exit_node_match;
++		}
++
++		node_match->id = id;
++		node_match->cur_rule = -1;
++		node_match->num_rules = 0;
++		node_match->data = data;
++		list_add_tail(&node_match->link, &node_list);
++		INIT_LIST_HEAD(&node_match->node_rules);
++		RAW_INIT_NOTIFIER_HEAD(&node_match->rule_notify_list);
++		pr_debug("Added new node %d to list\n", id);
++	}
++exit_node_match:
++	return node_match;
++}
++
++static bool do_compare_op(u64 op1, u64 op2, int op)
++{
++	bool ret = false;
++
++	switch (op) {
++	case OP_LE:
++		ret = LE(op1, op2);
++		break;
++	case OP_LT:
++		ret = LT(op1, op2);
++		break;
++	case OP_GT:
++		ret = GT(op1, op2);
++		break;
++	case OP_GE:
++		ret = GE(op1, op2);
++		break;
++	case OP_NOOP:
++		ret = true;
++		break;
++	default:
++		pr_info("Invalid OP %d", op);
++		break;
++	}
++	return ret;
++}
++
++static void update_src_id_vote(struct rule_update_path_info *inp_node,
++				struct rule_node_info *rule_node)
++{
++	struct rules_def *rule;
++	int i;
++
++	list_for_each_entry(rule, &rule_node->node_rules, link) {
++		for (i = 0; i < rule->num_src; i++) {
++			if (rule->src_info[i].id == inp_node->id) {
++				rule->src_info[i].ib = inp_node->ib;
++				rule->src_info[i].ab = inp_node->ab;
++				rule->src_info[i].clk = inp_node->clk;
++			}
++		}
++	}
++}
++
++static u64 get_field(struct rules_def *rule, int src_id)
++{
++	u64 field = 0;
++	int i;
++
++	for (i = 0; i < rule->num_src; i++) {
++		switch (rule->rule_ops.src_field) {
++		case FLD_IB:
++			field += rule->src_info[i].ib;
++			break;
++		case FLD_AB:
++			field += rule->src_info[i].ab;
++			break;
++		case FLD_CLK:
++			field += rule->src_info[i].clk;
++			break;
++		}
++	}
++
++	return field;
++}
++
++static bool check_rule(struct rules_def *rule,
++			struct rule_update_path_info *inp)
++{
++	bool ret = false;
++
++	if (!rule)
++		return ret;
++
++	switch (rule->rule_ops.op) {
++	case OP_LE:
++	case OP_LT:
++	case OP_GT:
++	case OP_GE:
++	{
++		u64 src_field = get_field(rule, inp->id);
++		if (!src_field)
++			ret = false;
++		else
++			ret = do_compare_op(src_field, rule->rule_ops.thresh,
++							rule->rule_ops.op);
++		break;
++	}
++	default:
++		pr_err("Unsupported op %d", rule->rule_ops.op);
++		break;
++	}
++	return ret;
++}
++
++static void match_rule(struct rule_update_path_info *inp_node,
++			struct rule_node_info *node)
++{
++	struct rules_def *rule;
++	int i;
++
++	list_for_each_entry(rule, &node->node_rules, link) {
++		for (i = 0; i < rule->num_src; i++) {
++			if (rule->src_info[i].id == inp_node->id) {
++				if (check_rule(rule, inp_node)) {
++					trace_bus_rules_matches(node->cur_rule,
++						inp_node->id, inp_node->ab,
++						inp_node->ib, inp_node->clk);
++					if (rule->state ==
++						RULE_STATE_NOT_APPLIED)
++						rule->state_change = true;
++					rule->state = RULE_STATE_APPLIED;
++				} else {
++					if (rule->state ==
++						RULE_STATE_APPLIED)
++						rule->state_change = true;
++					rule->state = RULE_STATE_NOT_APPLIED;
++				}
++			}
++		}
++	}
++}
++
++static void apply_rule(struct rule_node_info *node,
++			struct list_head *output_list)
++{
++	struct rules_def *rule;
++
++	node->cur_rule = -1;
++	list_for_each_entry(rule, &node->node_rules, link) {
++		if ((rule->state == RULE_STATE_APPLIED) &&
++						(node->cur_rule == -1))
++			node->cur_rule = rule->rule_id;
++
++		if (node->id == NB_ID) {
++			if (rule->state_change) {
++				rule->state_change = false;
++				raw_notifier_call_chain(&node->rule_notify_list,
++					rule->state, (void *)&rule->rule_ops);
++			}
++		} else {
++			if ((rule->state == RULE_STATE_APPLIED) &&
++				(node->cur_rule == rule->rule_id)) {
++				node->apply.id = rule->rule_ops.dst_node[0];
++				node->apply.throttle = rule->rule_ops.mode;
++				node->apply.lim_bw = rule->rule_ops.dst_bw;
++				list_add_tail(&node->apply.link, output_list);
++			}
++			rule->state_change = false;
++		}
++	}
++
++}
++
++int msm_rules_update_path(struct list_head *input_list,
++			struct list_head *output_list)
++{
++	int ret = 0;
++	struct rule_update_path_info  *inp_node;
++	struct rule_node_info *node_it = NULL;
++
++	mutex_lock(&msm_bus_rules_lock);
++	list_for_each_entry(inp_node, input_list, link) {
++		list_for_each_entry(node_it, &node_list, link) {
++			update_src_id_vote(inp_node, node_it);
++			match_rule(inp_node, node_it);
++		}
++	}
++
++	list_for_each_entry(node_it, &node_list, link)
++		apply_rule(node_it, output_list);
++
++	mutex_unlock(&msm_bus_rules_lock);
++	return ret;
++}
++
++static bool ops_equal(int op1, int op2)
++{
++	bool ret = false;
++
++	switch (op1) {
++	case OP_GT:
++	case OP_GE:
++	case OP_LT:
++	case OP_LE:
++		if (abs(op1 - op2) <= 1)
++			ret = true;
++		break;
++	default:
++		ret = (op1 == op2);
++	}
++
++	return ret;
++}
++
++static int node_rules_compare(void *priv, struct list_head *a,
++					struct list_head *b)
++{
++	struct rules_def *ra = container_of(a, struct rules_def, link);
++	struct rules_def *rb = container_of(b, struct rules_def, link);
++	int ret = -1;
++	int64_t th_diff = 0;
++
++
++	if (ra->rule_ops.mode == rb->rule_ops.mode) {
++		if (ops_equal(ra->rule_ops.op, rb->rule_ops.op)) {
++			if ((ra->rule_ops.op == OP_LT) ||
++				(ra->rule_ops.op == OP_LE)) {
++				th_diff = ra->rule_ops.thresh -
++						rb->rule_ops.thresh;
++				if (th_diff > 0)
++					ret = 1;
++				 else
++					ret = -1;
++			} else if ((ra->rule_ops.op == OP_GT) ||
++					(ra->rule_ops.op == OP_GE)) {
++				th_diff = rb->rule_ops.thresh -
++							ra->rule_ops.thresh;
++				if (th_diff > 0)
++					ret = 1;
++				 else
++					ret = -1;
++			}
++		} else
++			ret = ra->rule_ops.op - rb->rule_ops.op;
++	} else if ((ra->rule_ops.mode == THROTTLE_OFF) &&
++		(rb->rule_ops.mode == THROTTLE_ON)) {
++		ret = 1;
++	} else if ((ra->rule_ops.mode == THROTTLE_ON) &&
++		(rb->rule_ops.mode == THROTTLE_OFF)) {
++		ret = -1;
++	}
++
++	return ret;
++}
++
++static void print_rules(struct rule_node_info *node_it)
++{
++	struct rules_def *node_rule = NULL;
++	int i;
++
++	if (!node_it) {
++		pr_err("%s: no node for found", __func__);
++		return;
++	}
++
++	pr_info("\n Now printing rules for Node %d  cur rule %d\n",
++						node_it->id, node_it->cur_rule);
++	list_for_each_entry(node_rule, &node_it->node_rules, link) {
++		pr_info("\n num Rules %d  rule Id %d\n",
++				node_it->num_rules, node_rule->rule_id);
++		pr_info("Rule: src_field %d\n", node_rule->rule_ops.src_field);
++		for (i = 0; i < node_rule->rule_ops.num_src; i++)
++			pr_info("Rule: src %d\n",
++					node_rule->rule_ops.src_id[i]);
++		for (i = 0; i < node_rule->rule_ops.num_dst; i++)
++			pr_info("Rule: dst %d dst_bw %llu\n",
++						node_rule->rule_ops.dst_node[i],
++						node_rule->rule_ops.dst_bw);
++		pr_info("Rule: thresh %llu op %d mode %d State %d\n",
++					node_rule->rule_ops.thresh,
++					node_rule->rule_ops.op,
++					node_rule->rule_ops.mode,
++					node_rule->state);
++	}
++}
++
++void print_all_rules(void)
++{
++	struct rule_node_info *node_it = NULL;
++
++	list_for_each_entry(node_it, &node_list, link)
++		print_rules(node_it);
++}
++
++void print_rules_buf(char *buf, int max_buf)
++{
++	struct rule_node_info *node_it = NULL;
++	struct rules_def *node_rule = NULL;
++	int i;
++	int cnt = 0;
++
++	list_for_each_entry(node_it, &node_list, link) {
++		cnt += scnprintf(buf + cnt, max_buf - cnt,
++					"\n Now printing rules for Node %d cur_rule %d\n",
++					node_it->id, node_it->cur_rule);
++		list_for_each_entry(node_rule, &node_it->node_rules, link) {
++			cnt += scnprintf(buf + cnt, max_buf - cnt,
++				"\nNum Rules:%d ruleId %d STATE:%d change:%d\n",
++				node_it->num_rules, node_rule->rule_id,
++				node_rule->state, node_rule->state_change);
++			cnt += scnprintf(buf + cnt, max_buf - cnt,
++				"Src_field %d\n",
++				node_rule->rule_ops.src_field);
++			for (i = 0; i < node_rule->rule_ops.num_src; i++)
++				cnt += scnprintf(buf + cnt, max_buf - cnt,
++					"Src %d Cur Ib %llu Ab %llu\n",
++					node_rule->rule_ops.src_id[i],
++					node_rule->src_info[i].ib,
++					node_rule->src_info[i].ab);
++			for (i = 0; i < node_rule->rule_ops.num_dst; i++)
++				cnt += scnprintf(buf + cnt, max_buf - cnt,
++					"Dst %d dst_bw %llu\n",
++					node_rule->rule_ops.dst_node[0],
++					node_rule->rule_ops.dst_bw);
++			cnt += scnprintf(buf + cnt, max_buf - cnt,
++					"Thresh %llu op %d mode %d\n",
++					node_rule->rule_ops.thresh,
++					node_rule->rule_ops.op,
++					node_rule->rule_ops.mode);
++		}
++	}
++}
++
++static int copy_rule(struct bus_rule_type *src, struct rules_def *node_rule,
++			struct notifier_block *nb)
++{
++	int i;
++	int ret = 0;
++
++	memcpy(&node_rule->rule_ops, src,
++				sizeof(struct bus_rule_type));
++	node_rule->rule_ops.src_id = kzalloc(
++			(sizeof(int) * node_rule->rule_ops.num_src),
++							GFP_KERNEL);
++	if (!node_rule->rule_ops.src_id) {
++		pr_err("%s:Failed to allocate for src_id",
++					__func__);
++		return -ENOMEM;
++	}
++	memcpy(node_rule->rule_ops.src_id, src->src_id,
++				sizeof(int) * src->num_src);
++
++
++	if (!nb) {
++		node_rule->rule_ops.dst_node = kzalloc(
++			(sizeof(int) * node_rule->rule_ops.num_dst),
++						GFP_KERNEL);
++		if (!node_rule->rule_ops.dst_node) {
++			pr_err("%s:Failed to allocate for src_id",
++							__func__);
++			return -ENOMEM;
++		}
++		memcpy(node_rule->rule_ops.dst_node, src->dst_node,
++						sizeof(int) * src->num_dst);
++	}
++
++	node_rule->num_src = src->num_src;
++	node_rule->src_info = kzalloc(
++		(sizeof(struct node_vote_info) * node_rule->rule_ops.num_src),
++							GFP_KERNEL);
++	if (!node_rule->src_info) {
++		pr_err("%s:Failed to allocate for src_id",
++						__func__);
++		return -ENOMEM;
++	}
++	for (i = 0; i < src->num_src; i++)
++		node_rule->src_info[i].id = src->src_id[i];
++
++	return ret;
++}
++
++void msm_rule_register(int num_rules, struct bus_rule_type *rule,
++					struct notifier_block *nb)
++{
++	struct rule_node_info *node = NULL;
++	int i, j;
++	struct rules_def *node_rule = NULL;
++	int num_dst = 0;
++
++	if (!rule)
++		return;
++
++	mutex_lock(&msm_bus_rules_lock);
++	for (i = 0; i < num_rules; i++) {
++		if (nb)
++			num_dst = 1;
++		else
++			num_dst = rule[i].num_dst;
++
++		for (j = 0; j < num_dst; j++) {
++			int id = 0;
++
++			if (nb)
++				id = NB_ID;
++			else
++				id = rule[i].dst_node[j];
++
++			node = gen_node(id, nb);
++			if (!node) {
++				pr_info("Error getting rule");
++				goto exit_rule_register;
++			}
++			node_rule = kzalloc(sizeof(struct rules_def),
++						GFP_KERNEL);
++			if (!node_rule) {
++				pr_err("%s: Failed to allocate for rule",
++								__func__);
++				goto exit_rule_register;
++			}
++
++			if (copy_rule(&rule[i], node_rule, nb)) {
++				pr_err("Error copying rule");
++				goto exit_rule_register;
++			}
++
++			node_rule->rule_id = node->num_rules++;
++			if (nb)
++				node->data = nb;
++
++			list_add_tail(&node_rule->link, &node->node_rules);
++		}
++	}
++	list_sort(NULL, &node->node_rules, node_rules_compare);
++
++	if (nb)
++		raw_notifier_chain_register(&node->rule_notify_list, nb);
++exit_rule_register:
++	mutex_unlock(&msm_bus_rules_lock);
++	return;
++}
++
++static int comp_rules(struct bus_rule_type *rulea, struct bus_rule_type *ruleb)
++{
++	int ret = 1;
++
++	if (rulea->num_src == ruleb->num_src)
++		ret = memcmp(rulea->src_id, ruleb->src_id,
++				(sizeof(int) * rulea->num_src));
++	if (!ret && (rulea->num_dst == ruleb->num_dst))
++		ret = memcmp(rulea->dst_node, ruleb->dst_node,
++				(sizeof(int) * rulea->num_dst));
++	if (!ret && (rulea->dst_bw == ruleb->dst_bw) &&
++		(rulea->op == ruleb->op) && (rulea->thresh == ruleb->thresh))
++		ret = 0;
++
++	return ret;
++}
++
++void msm_rule_unregister(int num_rules, struct bus_rule_type *rule,
++					struct notifier_block *nb)
++{
++	int i;
++	struct rule_node_info *node = NULL;
++	struct rule_node_info *node_tmp = NULL;
++	struct rules_def *node_rule;
++	struct rules_def *node_rule_tmp;
++	bool match_found = false;
++
++	if (!rule)
++		return;
++
++	mutex_lock(&msm_bus_rules_lock);
++	if (nb) {
++		node = get_node(NB_ID, nb);
++		if (!node) {
++			pr_err("%s: Can't find node", __func__);
++			goto exit_unregister_rule;
++		}
++
++		list_for_each_entry_safe(node_rule, node_rule_tmp,
++					&node->node_rules, link) {
++			list_del(&node_rule->link);
++			kfree(node_rule);
++			node->num_rules--;
++		}
++		raw_notifier_chain_unregister(&node->rule_notify_list, nb);
++	} else {
++		for (i = 0; i < num_rules; i++) {
++			match_found = false;
++
++			list_for_each_entry(node, &node_list, link) {
++				list_for_each_entry_safe(node_rule,
++				node_rule_tmp, &node->node_rules, link) {
++					if (comp_rules(&node_rule->rule_ops,
++						&rule[i]) == 0) {
++						list_del(&node_rule->link);
++						kfree(node_rule);
++						match_found = true;
++						node->num_rules--;
++						list_sort(NULL,
++							&node->node_rules,
++							node_rules_compare);
++						break;
++					}
++				}
++			}
++		}
++	}
++
++	list_for_each_entry_safe(node, node_tmp,
++					&node_list, link) {
++		if (!node->num_rules) {
++			pr_debug("Deleting Rule node %d", node->id);
++			list_del(&node->link);
++			kfree(node);
++		}
++	}
++exit_unregister_rule:
++	mutex_unlock(&msm_bus_rules_lock);
++}
++
++bool msm_rule_are_rules_registered(void)
++{
++	bool ret = false;
++
++	if (list_empty(&node_list))
++		ret = false;
++	else
++		ret = true;
++
++	return ret;
++}
++
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_bus_rules.h
+@@ -0,0 +1,77 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef _ARCH_ARM_MACH_MSM_BUS_RULES_H
++#define _ARCH_ARM_MACH_MSM_BUS_RULES_H
++
++#include <linux/types.h>
++#include <linux/list.h>
++#include <linux/notifier.h>
++#include <dt-bindings/msm/msm-bus-rule-ops.h>
++
++#define MAX_NODES		(5)
++
++struct rule_update_path_info {
++	u32 id;
++	u64 ab;
++	u64 ib;
++	u64 clk;
++	struct list_head link;
++};
++
++struct rule_apply_rcm_info {
++	u32 id;
++	u64 lim_bw;
++	int throttle;
++	bool after_clk_commit;
++	struct list_head link;
++};
++
++struct bus_rule_type {
++	int num_src;
++	int *src_id;
++	int src_field;
++	int op;
++	u64 thresh;
++	int num_dst;
++	int *dst_node;
++	u64 dst_bw;
++	int mode;
++	void *client_data;
++};
++
++#if (defined(CONFIG_BUS_TOPOLOGY_ADHOC))
++void msm_rule_register(int num_rules, struct bus_rule_type *rule,
++				struct notifier_block *nb);
++void msm_rule_unregister(int num_rules, struct bus_rule_type *rule,
++						struct notifier_block *nb);
++void print_rules_buf(char *buf, int count);
++bool msm_rule_are_rules_registered(void);
++#else
++static inline void msm_rule_register(int num_rules, struct bus_rule_type *rule,
++				struct notifier_block *nb)
++{
++}
++static inline void msm_rule_unregister(int num_rules,
++					struct bus_rule_type *rule,
++					struct notifier_block *nb)
++{
++}
++static inline void print_rules_buf(char *buf, int count)
++{
++}
++static inline bool msm_rule_are_rules_registered(void)
++{
++	return false;
++}
++#endif /* defined(CONFIG_BUS_TOPOLOGY_ADHOC) */
++#endif /* _ARCH_ARM_MACH_MSM_BUS_RULES_H */
+--- /dev/null
++++ b/drivers/bus/msm_bus/msm_buspm_coresight_adhoc.c
+@@ -0,0 +1,189 @@
++/* Copyright (c) 2014 The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/uaccess.h>
++#include <linux/miscdevice.h>
++#include <linux/of_coresight.h>
++#include <linux/coresight.h>
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/list.h>
++
++struct msmbus_coresight_adhoc_clock_drvdata {
++	int				 id;
++	struct clk			*clk;
++	struct list_head		 list;
++};
++
++struct msmbus_coresight_adhoc_drvdata {
++	struct device			*dev;
++	struct coresight_device		*csdev;
++	struct coresight_desc		*desc;
++	struct list_head		 clocks;
++};
++
++static int msmbus_coresight_enable_adhoc(struct coresight_device *csdev)
++{
++	struct msmbus_coresight_adhoc_clock_drvdata *clk;
++	struct msmbus_coresight_adhoc_drvdata *drvdata =
++		dev_get_drvdata(csdev->dev.parent);
++	long rate;
++
++	list_for_each_entry(clk, &drvdata->clocks, list) {
++		if (clk->id == csdev->id) {
++			rate = clk_round_rate(clk->clk, 1L);
++			clk_set_rate(clk->clk, rate);
++			return clk_prepare_enable(clk->clk);
++		}
++	}
++
++	return -ENOENT;
++}
++
++static void msmbus_coresight_disable_adhoc(struct coresight_device *csdev)
++{
++	struct msmbus_coresight_adhoc_clock_drvdata *clk;
++	struct msmbus_coresight_adhoc_drvdata *drvdata =
++		dev_get_drvdata(csdev->dev.parent);
++
++	list_for_each_entry(clk, &drvdata->clocks, list) {
++		if (clk->id == csdev->id)
++			clk_disable_unprepare(clk->clk);
++	}
++}
++
++static const struct coresight_ops_source msmbus_coresight_adhoc_source_ops = {
++	.enable		= msmbus_coresight_enable_adhoc,
++	.disable	= msmbus_coresight_disable_adhoc,
++};
++
++static const struct coresight_ops msmbus_coresight_cs_ops = {
++	.source_ops	= &msmbus_coresight_adhoc_source_ops,
++};
++
++void msmbus_coresight_remove_adhoc(struct platform_device *pdev)
++{
++	struct msmbus_coresight_adhoc_clock_drvdata *clk, *next_clk;
++	struct msmbus_coresight_adhoc_drvdata *drvdata =
++		platform_get_drvdata(pdev);
++
++	msmbus_coresight_disable_adhoc(drvdata->csdev);
++	coresight_unregister(drvdata->csdev);
++	list_for_each_entry_safe(clk, next_clk, &drvdata->clocks, list) {
++		list_del(&clk->list);
++		devm_kfree(&pdev->dev, clk);
++	}
++	devm_kfree(&pdev->dev, drvdata->desc);
++	devm_kfree(&pdev->dev, drvdata);
++	platform_set_drvdata(pdev, NULL);
++}
++EXPORT_SYMBOL(msmbus_coresight_remove_adhoc);
++
++static int buspm_of_get_clk_adhoc(struct device_node *of_node,
++	struct msmbus_coresight_adhoc_drvdata *drvdata, int id)
++{
++	struct msmbus_coresight_adhoc_clock_drvdata *clk;
++	clk = devm_kzalloc(drvdata->dev, sizeof(*clk), GFP_KERNEL);
++
++	if (!clk)
++		return -ENOMEM;
++
++	clk->id = id;
++
++	clk->clk = of_clk_get_by_name(of_node, "bus_clk");
++	if (IS_ERR(clk->clk)) {
++		pr_err("Error: unable to get clock for coresight node %d\n",
++			id);
++		goto err;
++	}
++
++	list_add(&clk->list, &drvdata->clocks);
++	return 0;
++
++err:
++	devm_kfree(drvdata->dev, clk);
++	return -EINVAL;
++}
++
++int msmbus_coresight_init_adhoc(struct platform_device *pdev,
++		struct device_node *of_node)
++{
++	int ret;
++	struct device *dev = &pdev->dev;
++	struct coresight_platform_data *pdata;
++	struct msmbus_coresight_adhoc_drvdata *drvdata;
++	struct coresight_desc *desc;
++
++	pdata = of_get_coresight_platform_data(dev, of_node);
++	if (IS_ERR(pdata))
++		return PTR_ERR(pdata);
++
++	drvdata = platform_get_drvdata(pdev);
++	if (IS_ERR_OR_NULL(drvdata)) {
++		drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
++		if (!drvdata) {
++			pr_err("coresight: Alloc for drvdata failed\n");
++			return -ENOMEM;
++		}
++		INIT_LIST_HEAD(&drvdata->clocks);
++		drvdata->dev = &pdev->dev;
++		platform_set_drvdata(pdev, drvdata);
++	}
++	ret = buspm_of_get_clk_adhoc(of_node, drvdata, pdata->id);
++	if (ret) {
++		pr_err("Error getting clocks\n");
++		ret = -ENXIO;
++		goto err1;
++	}
++
++	desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
++	if (!desc) {
++		pr_err("coresight: Error allocating memory\n");
++		ret = -ENOMEM;
++		goto err1;
++	}
++
++	desc->type = CORESIGHT_DEV_TYPE_SOURCE;
++	desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_BUS;
++	desc->ops = &msmbus_coresight_cs_ops;
++	desc->pdata = pdata;
++	desc->dev = &pdev->dev;
++	desc->owner = THIS_MODULE;
++	drvdata->desc = desc;
++	drvdata->csdev = coresight_register(desc);
++	if (IS_ERR(drvdata->csdev)) {
++		pr_err("coresight: Coresight register failed\n");
++		ret = PTR_ERR(drvdata->csdev);
++		goto err0;
++	}
++
++	dev_info(dev, "msmbus_coresight initialized\n");
++
++	return 0;
++err0:
++	devm_kfree(dev, desc);
++err1:
++	devm_kfree(dev, drvdata);
++	platform_set_drvdata(pdev, NULL);
++	return ret;
++}
++EXPORT_SYMBOL(msmbus_coresight_init_adhoc);
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("MSM BusPM Adhoc CoreSight Driver");
+--- /dev/null
++++ b/drivers/bus/msm_bus/rpm-smd.h
+@@ -0,0 +1,268 @@
++/* Copyright (c) 2012, 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ */
++
++#ifndef __ARCH_ARM_MACH_MSM_RPM_SMD_H
++#define __ARCH_ARM_MACH_MSM_RPM_SMD_H
++
++/**
++ * enum msm_rpm_set - RPM enumerations for sleep/active set
++ * %MSM_RPM_CTX_SET_0: Set resource parameters for active mode.
++ * %MSM_RPM_CTX_SET_SLEEP: Set resource parameters for sleep.
++ */
++enum msm_rpm_set {
++	MSM_RPM_CTX_ACTIVE_SET,
++	MSM_RPM_CTX_SLEEP_SET,
++};
++
++struct msm_rpm_request;
++
++struct msm_rpm_kvp {
++	uint32_t key;
++	uint32_t length;
++	uint8_t *data;
++};
++#ifdef CONFIG_MSM_RPM_SMD
++/**
++ * msm_rpm_request() - Creates a parent element to identify the
++ * resource on the RPM, that stores the KVPs for different fields modified
++ * for a hardware resource
++ *
++ * @set: if the device is setting the active/sleep set parameter
++ * for the resource
++ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
++ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
++ * @num_elements: number of KVPs pairs associated with the resource
++ *
++ * returns pointer to a msm_rpm_request on success, NULL on error
++ */
++struct msm_rpm_request *msm_rpm_create_request(
++		enum msm_rpm_set set, uint32_t rsc_type,
++		uint32_t rsc_id, int num_elements);
++
++/**
++ * msm_rpm_request_noirq() - Creates a parent element to identify the
++ * resource on the RPM, that stores the KVPs for different fields modified
++ * for a hardware resource. This function is similar to msm_rpm_create_request
++ * except that it has to be called with interrupts masked.
++ *
++ * @set: if the device is setting the active/sleep set parameter
++ * for the resource
++ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
++ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
++ * @num_elements: number of KVPs pairs associated with the resource
++ *
++ * returns pointer to a msm_rpm_request on success, NULL on error
++ */
++struct msm_rpm_request *msm_rpm_create_request_noirq(
++		enum msm_rpm_set set, uint32_t rsc_type,
++		uint32_t rsc_id, int num_elements);
++
++/**
++ * msm_rpm_add_kvp_data() - Adds a Key value pair to a existing RPM resource.
++ *
++ * @handle: RPM resource handle to which the data should be appended
++ * @key:  unsigned integer identify the parameter modified
++ * @data: byte array that contains the value corresponding to key.
++ * @size:   size of data in bytes.
++ *
++ * returns 0 on success or errno
++ */
++int msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
++		uint32_t key, const uint8_t *data, int size);
++
++/**
++ * msm_rpm_add_kvp_data_noirq() - Adds a Key value pair to a existing RPM
++ * resource. This function is similar to msm_rpm_add_kvp_data except that it
++ * has to be called with interrupts masked.
++ *
++ * @handle: RPM resource handle to which the data should be appended
++ * @key:  unsigned integer identify the parameter modified
++ * @data: byte array that contains the value corresponding to key.
++ * @size:   size of data in bytes.
++ *
++ * returns 0 on success or errno
++ */
++int msm_rpm_add_kvp_data_noirq(struct msm_rpm_request *handle,
++		uint32_t key, const uint8_t *data, int size);
++
++/** msm_rpm_free_request() - clean up the RPM request handle created with
++ * msm_rpm_create_request
++ *
++ * @handle: RPM resource handle to be cleared.
++ */
++
++void msm_rpm_free_request(struct msm_rpm_request *handle);
++
++/**
++ * msm_rpm_send_request() - Send the RPM messages using SMD. The function
++ * assigns a message id before sending the data out to the RPM. RPM hardware
++ * uses the message id to acknowledge the messages.
++ *
++ * @handle: pointer to the msm_rpm_request for the resource being modified.
++ *
++ * returns non-zero message id on success and zero on a failed transaction.
++ * The drivers use message id to wait for ACK from RPM.
++ */
++int msm_rpm_send_request(struct msm_rpm_request *handle);
++
++/**
++ * msm_rpm_send_request_noirq() - Send the RPM messages using SMD. The
++ * function assigns a message id before sending the data out to the RPM.
++ * RPM hardware uses the message id to acknowledge the messages. This function
++ * is similar to msm_rpm_send_request except that it has to be called with
++ * interrupts masked.
++ *
++ * @handle: pointer to the msm_rpm_request for the resource being modified.
++ *
++ * returns non-zero message id on success and zero on a failed transaction.
++ * The drivers use message id to wait for ACK from RPM.
++ */
++int msm_rpm_send_request_noirq(struct msm_rpm_request *handle);
++
++/**
++ * msm_rpm_wait_for_ack() - A blocking call that waits for acknowledgment of
++ * a message from RPM.
++ *
++ * @msg_id: the return from msm_rpm_send_requests
++ *
++ * returns 0 on success or errno
++ */
++int msm_rpm_wait_for_ack(uint32_t msg_id);
++
++/**
++ * msm_rpm_wait_for_ack_noirq() - A blocking call that waits for acknowledgment
++ * of a message from RPM. This function is similar to msm_rpm_wait_for_ack
++ * except that it has to be called with interrupts masked.
++ *
++ * @msg_id: the return from msm_rpm_send_request
++ *
++ * returns 0 on success or errno
++ */
++int msm_rpm_wait_for_ack_noirq(uint32_t msg_id);
++
++/**
++ * msm_rpm_send_message() -Wrapper function for clients to send data given an
++ * array of key value pairs.
++ *
++ * @set: if the device is setting the active/sleep set parameter
++ * for the resource
++ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
++ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
++ * @kvp: array of KVP data.
++ * @nelem: number of KVPs pairs associated with the message.
++ *
++ * returns  0 on success and errno on failure.
++ */
++int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type,
++		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems);
++
++/**
++ * msm_rpm_send_message_noirq() -Wrapper function for clients to send data
++ * given an array of key value pairs. This function is similar to the
++ * msm_rpm_send_message() except that it has to be called with interrupts
++ * disabled. Clients should choose the irq version when possible for system
++ * performance.
++ *
++ * @set: if the device is setting the active/sleep set parameter
++ * for the resource
++ * @rsc_type: unsigned 32 bit integer that identifies the type of the resource
++ * @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
++ * @kvp: array of KVP data.
++ * @nelem: number of KVPs pairs associated with the message.
++ *
++ * returns  0 on success and errno on failure.
++ */
++int msm_rpm_send_message_noirq(enum msm_rpm_set set, uint32_t rsc_type,
++		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems);
++
++/**
++ * msm_rpm_driver_init() - Initialization function that registers for a
++ * rpm platform driver.
++ *
++ * returns 0 on success.
++ */
++int __init msm_rpm_driver_init(void);
++
++#else
++
++static inline struct msm_rpm_request *msm_rpm_create_request(
++		enum msm_rpm_set set, uint32_t rsc_type,
++		uint32_t rsc_id, int num_elements)
++{
++	return NULL;
++}
++
++static inline struct msm_rpm_request *msm_rpm_create_request_noirq(
++		enum msm_rpm_set set, uint32_t rsc_type,
++		uint32_t rsc_id, int num_elements)
++{
++	return NULL;
++
++}
++static inline uint32_t msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
++		uint32_t key, const uint8_t *data, int count)
++{
++	return 0;
++}
++static inline uint32_t msm_rpm_add_kvp_data_noirq(
++		struct msm_rpm_request *handle, uint32_t key,
++		const uint8_t *data, int count)
++{
++	return 0;
++}
++
++static inline void msm_rpm_free_request(struct msm_rpm_request *handle)
++{
++	return;
++}
++
++static inline int msm_rpm_send_request(struct msm_rpm_request *handle)
++{
++	return 0;
++}
++
++static inline int msm_rpm_send_request_noirq(struct msm_rpm_request *handle)
++{
++	return 0;
++
++}
++
++static inline int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type,
++		uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems)
++{
++	return 0;
++}
++
++static inline int msm_rpm_send_message_noirq(enum msm_rpm_set set,
++		uint32_t rsc_type, uint32_t rsc_id, struct msm_rpm_kvp *kvp,
++		int nelems)
++{
++	return 0;
++}
++
++static inline int msm_rpm_wait_for_ack(uint32_t msg_id)
++{
++	return 0;
++
++}
++static inline int msm_rpm_wait_for_ack_noirq(uint32_t msg_id)
++{
++	return 0;
++}
++
++static inline int __init msm_rpm_driver_init(void)
++{
++	return 0;
++}
++#endif
++#endif /*__ARCH_ARM_MACH_MSM_RPM_SMD_H*/
+--- /dev/null
++++ b/include/trace/events/trace_msm_bus.h
+@@ -0,0 +1,163 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#undef TRACE_SYSTEM
++#define TRACE_SYSTEM msm_bus
++
++#if !defined(_TRACE_MSM_BUS_H) || defined(TRACE_HEADER_MULTI_READ)
++#define _TRACE_MSM_BUS_H
++
++#include <linux/tracepoint.h>
++
++TRACE_EVENT(bus_update_request,
++
++	TP_PROTO(int sec, int nsec, const char *name, unsigned int index,
++		int src, int dest, unsigned long long ab,
++		unsigned long long ib),
++
++	TP_ARGS(sec, nsec, name, index, src, dest, ab, ib),
++
++	TP_STRUCT__entry(
++		__field(int, sec)
++		__field(int, nsec)
++		__string(name, name)
++		__field(u32, index)
++		__field(int, src)
++		__field(int, dest)
++		__field(u64, ab)
++		__field(u64, ib)
++	),
++
++	TP_fast_assign(
++		__entry->sec = sec;
++		__entry->nsec = nsec;
++		__assign_str(name, name);
++		__entry->index = index;
++		__entry->src = src;
++		__entry->dest = dest;
++		__entry->ab = ab;
++		__entry->ib = ib;
++	),
++
++	TP_printk("time= %d.%d name=%s index=%u src=%d dest=%d ab=%llu ib=%llu",
++		__entry->sec,
++		__entry->nsec,
++		__get_str(name),
++		(unsigned int)__entry->index,
++		__entry->src,
++		__entry->dest,
++		(unsigned long long)__entry->ab,
++		(unsigned long long)__entry->ib)
++);
++
++TRACE_EVENT(bus_bimc_config_limiter,
++
++	TP_PROTO(int mas_id, unsigned long long cur_lim_bw),
++
++	TP_ARGS(mas_id, cur_lim_bw),
++
++	TP_STRUCT__entry(
++		__field(int, mas_id)
++		__field(u64, cur_lim_bw)
++	),
++
++	TP_fast_assign(
++		__entry->mas_id = mas_id;
++		__entry->cur_lim_bw = cur_lim_bw;
++	),
++
++	TP_printk("Master=%d cur_lim_bw=%llu",
++		__entry->mas_id,
++		(unsigned long long)__entry->cur_lim_bw)
++);
++
++TRACE_EVENT(bus_avail_bw,
++
++	TP_PROTO(unsigned long long cur_bimc_bw, unsigned long long cur_mdp_bw),
++
++	TP_ARGS(cur_bimc_bw, cur_mdp_bw),
++
++	TP_STRUCT__entry(
++		__field(u64, cur_bimc_bw)
++		__field(u64, cur_mdp_bw)
++	),
++
++	TP_fast_assign(
++		__entry->cur_bimc_bw = cur_bimc_bw;
++		__entry->cur_mdp_bw = cur_mdp_bw;
++	),
++
++	TP_printk("cur_bimc_bw = %llu cur_mdp_bw = %llu",
++		(unsigned long long)__entry->cur_bimc_bw,
++		(unsigned long long)__entry->cur_mdp_bw)
++);
++
++TRACE_EVENT(bus_rules_matches,
++
++	TP_PROTO(int node_id, int rule_id, unsigned long long node_ab,
++		unsigned long long node_ib, unsigned long long node_clk),
++
++	TP_ARGS(node_id, rule_id, node_ab, node_ib, node_clk),
++
++	TP_STRUCT__entry(
++		__field(int, node_id)
++		__field(int, rule_id)
++		__field(u64, node_ab)
++		__field(u64, node_ib)
++		__field(u64, node_clk)
++	),
++
++	TP_fast_assign(
++		__entry->node_id = node_id;
++		__entry->rule_id = rule_id;
++		__entry->node_ab = node_ab;
++		__entry->node_ib = node_ib;
++		__entry->node_clk = node_clk;
++	),
++
++	TP_printk("Rule match node%d rule%d node-ab%llu:ib%llu:clk%llu",
++		__entry->node_id, __entry->rule_id,
++		(unsigned long long)__entry->node_ab,
++		(unsigned long long)__entry->node_ib,
++		(unsigned long long)__entry->node_clk)
++);
++
++TRACE_EVENT(bus_bke_params,
++
++	TP_PROTO(u32 gc, u32 gp, u32 thl, u32 thm, u32 thh),
++
++	TP_ARGS(gc, gp, thl, thm, thh),
++
++	TP_STRUCT__entry(
++		__field(u32, gc)
++		__field(u32, gp)
++		__field(u32, thl)
++		__field(u32, thm)
++		__field(u32, thh)
++	),
++
++	TP_fast_assign(
++		__entry->gc = gc;
++		__entry->gp = gp;
++		__entry->thl = thl;
++		__entry->thm = thm;
++		__entry->thh = thh;
++	),
++
++	TP_printk("BKE Params GC=0x%x GP=0x%x THL=0x%x THM=0x%x THH=0x%x",
++		__entry->gc, __entry->gp, __entry->thl, __entry->thm,
++			__entry->thh)
++);
++
++#endif
++#define TRACE_INCLUDE_FILE trace_msm_bus
++#include <trace/define_trace.h>
diff --git a/target/linux/ipq806x/patches-4.14/850-soc-add-qualcomm-syscon.patch b/target/linux/ipq806x/patches-4.14/850-soc-add-qualcomm-syscon.patch
new file mode 100644
index 0000000..c6a9176
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.14/850-soc-add-qualcomm-syscon.patch
@@ -0,0 +1,177 @@ 
+From: Christian Lamparter <chunkeey@googlemail.com>
+Subject: SoC: add qualcomm syscon
+--- a/drivers/soc/qcom/Makefile
++++ b/drivers/soc/qcom/Makefile
+@@ -9,3 +9,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_st
+ obj-$(CONFIG_QCOM_SMP2P)	+= smp2p.o
+ obj-$(CONFIG_QCOM_SMSM)	+= smsm.o
+ obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
++obj-$(CONFIG_QCOM_TCSR)	 += qcom_tcsr.o
+--- a/drivers/soc/qcom/Kconfig
++++ b/drivers/soc/qcom/Kconfig
+@@ -78,6 +78,13 @@ config QCOM_SMSM
+	  Say yes here to support the Qualcomm Shared Memory State Machine.
+	  The state machine is represented by bits in shared memory.
+
++config QCOM_TCSR
++	tristate "QCOM Top Control and Status Registers"
++	depends on ARCH_QCOM
++	help
++	  Say y here to enable TCSR support.  The TCSR provides control
++	  functions for various peripherals.
++
+ config QCOM_WCNSS_CTRL
+	tristate "Qualcomm WCNSS control driver"
+	depends on ARCH_QCOM
+--- /dev/null
++++ b/drivers/soc/qcom/qcom_tcsr.c
+@@ -0,0 +1,98 @@
++/*
++ * Copyright (c) 2014, The Linux foundation. 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 rev 2 and
++ * only rev 2 as published by the free Software foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or fITNESS fOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++
++#define TCSR_USB_PORT_SEL	0xb0
++#define TCSR_USB_HSPHY_CONFIG	0xC
++
++#define TCSR_ESS_INTERFACE_SEL_OFFSET   0x0
++#define TCSR_ESS_INTERFACE_SEL_MASK     0xf
++
++#define TCSR_WIFI0_GLB_CFG_OFFSET	0x0
++#define TCSR_WIFI1_GLB_CFG_OFFSET	0x4
++#define TCSR_PNOC_SNOC_MEMTYPE_M0_M2	0x4
++
++static int tcsr_probe(struct platform_device *pdev)
++{
++	struct resource *res;
++	const struct device_node *node = pdev->dev.of_node;
++	void __iomem *base;
++	u32 val;
++
++	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++	base = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(base))
++		return PTR_ERR(base);
++
++	if (!of_property_read_u32(node, "qcom,usb-ctrl-select", &val)) {
++		dev_err(&pdev->dev, "setting usb port select = %d\n", val);
++		writel(val, base + TCSR_USB_PORT_SEL);
++	}
++
++	if (!of_property_read_u32(node, "qcom,usb-hsphy-mode-select", &val)) {
++		dev_info(&pdev->dev, "setting usb hs phy mode select = %x\n", val);
++		writel(val, base + TCSR_USB_HSPHY_CONFIG);
++	}
++
++	if (!of_property_read_u32(node, "qcom,ess-interface-select", &val)) {
++		u32 tmp = 0;
++		dev_info(&pdev->dev, "setting ess interface select = %x\n", val);
++		tmp = readl(base + TCSR_ESS_INTERFACE_SEL_OFFSET);
++		tmp = tmp & (~TCSR_ESS_INTERFACE_SEL_MASK);
++		tmp = tmp | (val&TCSR_ESS_INTERFACE_SEL_MASK);
++		writel(tmp, base + TCSR_ESS_INTERFACE_SEL_OFFSET);
++        }
++
++	if (!of_property_read_u32(node, "qcom,wifi_glb_cfg", &val)) {
++		dev_info(&pdev->dev, "setting wifi_glb_cfg = %x\n", val);
++		writel(val, base + TCSR_WIFI0_GLB_CFG_OFFSET);
++		writel(val, base + TCSR_WIFI1_GLB_CFG_OFFSET);
++	}
++
++	if (!of_property_read_u32(node, "qcom,wifi_noc_memtype_m0_m2", &val)) {
++		dev_info(&pdev->dev,
++			"setting wifi_noc_memtype_m0_m2 = %x\n", val);
++		writel(val, base + TCSR_PNOC_SNOC_MEMTYPE_M0_M2);
++	}
++
++	return 0;
++}
++
++static const struct of_device_id tcsr_dt_match[] = {
++	{ .compatible = "qcom,tcsr", },
++	{ },
++};
++
++MODULE_DEVICE_TABLE(of, tcsr_dt_match);
++
++static struct platform_driver tcsr_driver = {
++	.driver = {
++		.name		= "tcsr",
++		.owner		= THIS_MODULE,
++		.of_match_table	= tcsr_dt_match,
++	},
++	.probe = tcsr_probe,
++};
++
++module_platform_driver(tcsr_driver);
++
++MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
++MODULE_DESCRIPTION("QCOM TCSR driver");
++MODULE_LICENSE("GPL v2");
+--- /dev/null
++++ b/include/dt-bindings/soc/qcom,tcsr.h
+@@ -0,0 +1,48 @@
++/* Copyright (c) 2014, The Linux Foundation. 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 and
++ * only version 2 as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++#ifndef __DT_BINDINGS_QCOM_TCSR_H
++#define __DT_BINDINGS_QCOM_TCSR_H
++
++#define TCSR_USB_SELECT_USB3_P0		0x1
++#define TCSR_USB_SELECT_USB3_P1		0x2
++#define TCSR_USB_SELECT_USB3_DUAL	0x3
++
++/* IPQ40xx HS PHY Mode Select */
++#define TCSR_USB_HSPHY_HOST_MODE	0x00E700E7
++#define TCSR_USB_HSPHY_DEVICE_MODE	0x00C700E7
++
++/* IPQ40xx ess interface mode select */
++#define TCSR_ESS_PSGMII              0
++#define TCSR_ESS_PSGMII_RGMII5       1
++#define TCSR_ESS_PSGMII_RMII0        2
++#define TCSR_ESS_PSGMII_RMII1        4
++#define TCSR_ESS_PSGMII_RMII0_RMII1  6
++#define TCSR_ESS_PSGMII_RGMII4       9
++
++/*
++ * IPQ40xx WiFi Global Config
++ * Bit 30:AXID_EN
++ * Enable AXI master bus Axid translating to confirm all txn submitted by order
++ * Bit 24: Use locally generated socslv_wxi_bvalid
++ * 1:  use locally generate socslv_wxi_bvalid for performance.
++ * 0:  use SNOC socslv_wxi_bvalid.
++ */
++#define TCSR_WIFI_GLB_CFG		0x41000000
++
++/* IPQ40xx MEM_TYPE_SEL_M0_M2 Select Bit 26:24 - 2 NORMAL */
++#define TCSR_WIFI_NOC_MEMTYPE_M0_M2	0x02222222
++
++/* TCSR A/B REG */
++#define IPQ806X_TCSR_REG_A_ADM_CRCI_MUX_SEL     0
++#define IPQ806X_TCSR_REG_B_ADM_CRCI_MUX_SEL     1
++
++#endif