All of lore.kernel.org
 help / color / mirror / Atom feed
From: rosysong at rosinson.com <rosysong@rosinson.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [U-Boot, V4, PATCH 1/1] mips: add initial support for qca956x referenced board
Date: Fri,  8 Mar 2019 09:24:26 +0800	[thread overview]
Message-ID: <20190308012426.13605-1-rosysong@rosinson.com> (raw)

From: Rosy Song <rosysong@rosinson.com>

QCA9563 is CPU used on AP152 board :

    Clock speed : 750 MHz ,
    Arch :  Mips 74Kc,
    Eth : SGMII interface,
    MIMO config : 3 * 3 450M,
    2 * USB 2.0,

Signed-off-by: Rosy Song <rosysong@rosinson.com>

Changes for v2:
   - coding Style cleanup
   - remove ununsed flash chip in defconfig
   - enable automatic icache / dcache size in defconfig

Changes for v3:
   - add detailed information for qca956x in commit message

Changes for v4:
   - remove pre-configured network settings in ap152.h
---
 arch/mips/dts/Makefile                        |   1 +
 arch/mips/dts/ap152.dts                       |  48 ++
 arch/mips/dts/qca956x.dtsi                    |  87 ++++
 arch/mips/mach-ath79/Kconfig                  |  14 +
 arch/mips/mach-ath79/Makefile                 |   1 +
 .../mach-ath79/include/mach/ar71xx_regs.h     |  73 +++
 arch/mips/mach-ath79/include/mach/ath79.h     |   3 +
 arch/mips/mach-ath79/qca956x/Makefile         |   5 +
 arch/mips/mach-ath79/qca956x/clk.c            | 419 ++++++++++++++++++
 arch/mips/mach-ath79/qca956x/cpu.c            |   9 +
 arch/mips/mach-ath79/qca956x/ddr.c            | 308 +++++++++++++
 .../mips/mach-ath79/qca956x/qca956x-ddr-tap.S | 193 ++++++++
 arch/mips/mach-ath79/reset.c                  | 271 +++++++++++
 board/qca/ap152/Kconfig                       |  15 +
 board/qca/ap152/MAINTAINERS                   |   6 +
 board/qca/ap152/Makefile                      |   3 +
 board/qca/ap152/ap152.c                       |  81 ++++
 configs/ap152_defconfig                       |  49 ++
 include/configs/ap152.h                       |  50 +++
 19 files changed, 1636 insertions(+)
 create mode 100644 arch/mips/dts/ap152.dts
 create mode 100644 arch/mips/dts/qca956x.dtsi
 create mode 100644 arch/mips/mach-ath79/qca956x/Makefile
 create mode 100644 arch/mips/mach-ath79/qca956x/clk.c
 create mode 100644 arch/mips/mach-ath79/qca956x/cpu.c
 create mode 100644 arch/mips/mach-ath79/qca956x/ddr.c
 create mode 100644 arch/mips/mach-ath79/qca956x/qca956x-ddr-tap.S
 create mode 100644 board/qca/ap152/Kconfig
 create mode 100644 board/qca/ap152/MAINTAINERS
 create mode 100644 board/qca/ap152/Makefile
 create mode 100644 board/qca/ap152/ap152.c
 create mode 100644 configs/ap152_defconfig
 create mode 100644 include/configs/ap152.h

diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
index b94b582837..621c35f0ef 100644
--- a/arch/mips/dts/Makefile
+++ b/arch/mips/dts/Makefile
@@ -2,6 +2,7 @@
 
 dtb-$(CONFIG_TARGET_AP121) += ap121.dtb
 dtb-$(CONFIG_TARGET_AP143) += ap143.dtb
+dtb-$(CONFIG_TARGET_AP152) += ap152.dtb
 dtb-$(CONFIG_TARGET_BOSTON) += img,boston.dtb
 dtb-$(CONFIG_TARGET_MALTA) += mti,malta.dtb
 dtb-$(CONFIG_TARGET_PIC32MZDASK) += pic32mzda_sk.dtb
diff --git a/arch/mips/dts/ap152.dts b/arch/mips/dts/ap152.dts
new file mode 100644
index 0000000000..1722290c73
--- /dev/null
+++ b/arch/mips/dts/ap152.dts
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Rosy Song <rosysong@rosinson.com>
+ */
+
+/dts-v1/;
+#include "qca956x.dtsi"
+
+/ {
+	model = "AP152 Reference Board";
+	compatible = "qca,ap152", "qca,qca956x";
+
+	aliases {
+		spi0 = &spi0;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&gmac0 {
+	phy-mode = "sgmii";
+	status = "okay";
+};
+
+&xtal {
+	clock-frequency = <25000000>;
+};
+
+&uart0 {
+	clock-frequency = <25000000>;
+	status = "okay";
+};
+
+&spi0 {
+	spi-max-frequency = <25000000>;
+	status = "okay";
+	spi-flash at 0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-flash";
+		memory-map = <0x9f000000 0x01000000>;
+		spi-max-frequency = <25000000>;
+		reg = <0>;
+	};
+};
diff --git a/arch/mips/dts/qca956x.dtsi b/arch/mips/dts/qca956x.dtsi
new file mode 100644
index 0000000000..6cb360b3f8
--- /dev/null
+++ b/arch/mips/dts/qca956x.dtsi
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Rosy Song <rosysong@rosinson.com>
+ */
+
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "qca,qca956x";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu at 0 {
+			device_type = "cpu";
+			compatible = "mips,mips74Kc";
+			reg = <0>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		xtal: xtal {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-output-names = "xtal";
+		};
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		ranges;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		apb {
+			compatible = "simple-bus";
+			ranges;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			uart0: uart at 18020000 {
+				compatible = "ns16550";
+				reg = <0x18020000 0x20>;
+				reg-shift = <2>;
+
+				status = "disabled";
+			};
+
+			gmac0: eth at 0x19000000 {
+				compatible = "qca,ag956x-mac";
+				reg = <0x19000000 0x200>;
+				phy = <&phy0>;
+				phy-mode = "sgmii";
+
+				status = "disabled";
+
+				mdio {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					phy0: ethernet-phy at 0 {
+						reg = <0>;
+					};
+				};
+			};
+		};
+
+		spi0: spi at 1f000000 {
+			compatible = "qca,ar7100-spi";
+			reg = <0x1f000000 0x10>;
+
+			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig
index bc86f591df..bdb23b5765 100644
--- a/arch/mips/mach-ath79/Kconfig
+++ b/arch/mips/mach-ath79/Kconfig
@@ -33,6 +33,15 @@ config SOC_QCA953X
 	help
 	  This supports QCA/Atheros qca953x family SOCs.
 
+config SOC_QCA956X
+	bool
+	select MIPS_TUNE_74KC
+	select SUPPORTS_BIG_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	help
+	  This supports QCA/Atheros qca956x family SOCs.
+
 choice
 	prompt "Board select"
 
@@ -44,6 +53,10 @@ config TARGET_AP143
 	bool "AP143 Reference Board"
 	select SOC_QCA953X
 
+config TARGET_AP152
+	bool "AP152 Reference Board"
+	select SOC_QCA956X
+
 config BOARD_TPLINK_WDR4300
 	bool "TP-Link WDR4300 Board"
 	select SOC_AR934X
@@ -52,6 +65,7 @@ endchoice
 
 source "board/qca/ap121/Kconfig"
 source "board/qca/ap143/Kconfig"
+source "board/qca/ap152/Kconfig"
 source "board/tplink/wdr4300/Kconfig"
 
 endmenu
diff --git a/arch/mips/mach-ath79/Makefile b/arch/mips/mach-ath79/Makefile
index 7aa40c65d3..fbd40c02be 100644
--- a/arch/mips/mach-ath79/Makefile
+++ b/arch/mips/mach-ath79/Makefile
@@ -7,3 +7,4 @@ obj-y += dram.o
 obj-$(CONFIG_SOC_AR933X)	+= ar933x/
 obj-$(CONFIG_SOC_AR934X)	+= ar934x/
 obj-$(CONFIG_SOC_QCA953X)	+= qca953x/
+obj-$(CONFIG_SOC_QCA956X)	+= qca956x/
diff --git a/arch/mips/mach-ath79/include/mach/ar71xx_regs.h b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
index 5d371bb582..7cd16b8d81 100644
--- a/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
+++ b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
@@ -194,6 +194,9 @@
 #define QCA956X_WMAC_BASE \
 	(AR71XX_APB_BASE + 0x00100000)
 #define QCA956X_WMAC_SIZE				0x20000
+#define QCA956X_RTC_BASE \
+	(AR71XX_APB_BASE + 0x00107000)
+#define QCA956X_RTC_SIZE					0x1000
 #define QCA956X_EHCI0_BASE				0x1b000000
 #define QCA956X_EHCI1_BASE				0x1b400000
 #define QCA956X_EHCI_SIZE				0x200
@@ -201,6 +204,10 @@
 	(AR71XX_APB_BASE + 0x00070000)
 #define QCA956X_GMAC_SIZE				0x64
 
+#define QCA956X_SRIF_BASE \
+	(AR71XX_APB_BASE + 0x00116000)
+#define QCA956X_SRIF_SIZE				0x1000
+
 /*
  * DDR_CTRL block
  */
@@ -278,6 +285,18 @@
 #define QCA953X_DDR_REG_CTL_CONF			0x108
 #define QCA953X_DDR_REG_CONFIG3				0x15c
 
+#define QCA956X_DDR_REG_TAP_CTRL2			0x24
+#define QCA956X_DDR_REG_TAP_CTRL3			0x28
+#define QCA956X_DDR_REG_DDR2_CONFIG			0xb8
+#define QCA956X_DDR_REG_DDR2_EMR2			0xbc
+#define QCA956X_DDR_REG_DDR2_EMR3			0xc0
+#define QCA956X_DDR_REG_BURST				0xc4
+#define QCA956X_DDR_REG_BURST2				0xc8
+#define QCA956X_DDR_REG_TIMEOUT_MAX			0xcc
+#define QCA956X_DDR_REG_FSM_WAIT_CTRL			0xe4
+#define QCA956X_DDR_REG_CTL_CONF			0x108
+#define QCA956X_DDR_REG_DDR3_CONFIG			0x15c
+
 /*
  * PLL block
  */
@@ -519,6 +538,13 @@
 #define QCA956X_PLL_DDR_CONFIG_REG			0x08
 #define QCA956X_PLL_DDR_CONFIG1_REG			0x0c
 #define QCA956X_PLL_CLK_CTRL_REG			0x10
+#define QCA956X_PLL_SWITCH_CLK_CTRL_REG			0x28
+#define QCA956X_PLL_ETH_XMII_CTRL_REG			0x30
+#define QCA956X_PLL_DDR_DIT_FRAC_REG			0x38
+#define QCA956X_PLL_DDR_DIT2_FRAC_REG			0x3c
+#define QCA956X_PLL_CPU_DIT_FRAC_REG			0x40
+#define QCA956X_PLL_CPU_DIT2_FRAC_REG			0x44
+#define QCA956X_PLL_ETH_SGMII_SERDES_REG		0x4c
 
 #define QCA956X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
 #define QCA956X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
@@ -756,6 +782,17 @@
 #define QCA955X_RESET_MBOX				BIT(1)
 #define QCA955X_RESET_I2S				BIT(0)
 
+#define QCA956X_RESET_EXTERNAL				BIT(28)
+#define QCA956X_RESET_FULL_CHIP				BIT(24)
+#define QCA956X_RESET_GE1_MDIO				BIT(23) /* Reserved in datasheet */
+#define QCA956X_RESET_GE0_MDIO				BIT(22)
+#define QCA956X_RESET_GE1_MAC				BIT(13) /* Reserved in datasheet */
+#define QCA956X_RESET_SGMII_ASSERT			BIT(12)
+#define QCA956X_RESET_GE0_MAC				BIT(9)
+#define QCA956X_RESET_SGMII				BIT(8)
+#define QCA956X_RESET_SGMII_ANALOG				BIT(2)
+#define QCA956X_RESET_SWITCH				BIT(0)
+
 #define AR933X_BOOTSTRAP_MDIO_GPIO_EN			BIT(18)
 #define AR933X_BOOTSTRAP_DDR2				BIT(13)
 #define AR933X_BOOTSTRAP_EEPBUSY			BIT(4)
@@ -1099,8 +1136,12 @@
 #define QCA953X_GPIO_IN_MUX_UART0_SIN			9
 #define QCA953X_GPIO_IN_MUX_SPI_DATA_IN			8
 
+#define QCA956X_GPIO(x)					BIT(x)
+#define QCA956X_GPIO_MUX_MASK(x)			(0xff << (x))
 #define QCA956X_GPIO_OUT_MUX_GE0_MDO			32
 #define QCA956X_GPIO_OUT_MUX_GE0_MDC			33
+#define QCA956X_GPIO_IN_MUX_UART0_SIN			0x12
+#define QCA956X_GPIO_OUT_MUX_UART0_SOUT			0x16
 
 #define AR71XX_GPIO_COUNT				16
 #define AR7240_GPIO_COUNT				18
@@ -1179,6 +1220,25 @@
 #define QCA953X_SRIF_DPLL2_OUTDIV_SHIFT			13
 #define QCA953X_SRIF_DPLL2_OUTDIV_MASK			0x7
 
+#define QCA956X_SRIF_BB_DPLL1_REG			0x180
+#define QCA956X_SRIF_BB_DPLL2_REG			0x184
+#define QCA956X_SRIF_BB_DPLL3_REG			0x188
+
+#define QCA956X_SRIF_CPU_DPLL1_REG			0xf00
+#define QCA956X_SRIF_CPU_DPLL2_REG			0xf04
+#define QCA956X_SRIF_CPU_DPLL3_REG			0xf08
+
+#define QCA956X_SRIF_DDR_DPLL1_REG			0xec0
+#define QCA956X_SRIF_DDR_DPLL2_REG			0xec4
+#define QCA956X_SRIF_DDR_DPLL3_REG			0xec8
+
+#define QCA956X_SRIF_PCIE_DPLL1_REG			0xc80
+#define QCA956X_SRIF_PCIE_DPLL2_REG			0xc84
+#define QCA956X_SRIF_PCIE_DPLL3_REG			0xc88
+
+#define QCA956X_SRIF_PMU1_REG				0xcc0
+#define QCA956X_SRIF_PMU2_REG				0xcc4
+
 /*
  * MII_CTRL block
  */
@@ -1261,4 +1321,17 @@
 #define QCA955X_ETH_CFG_RGMII_EN			BIT(0)
 #define QCA955X_ETH_CFG_GE0_SGMII			BIT(6)
 
+/*
+ * QCA956X GMAC Interface
+ */
+
+#define QCA956X_GMAC_REG_ETH_CFG			0x00
+#define QCA956X_GMAC_REG_SGMII_RESET			0x14
+#define QCA956X_GMAC_REG_SGMII_SERDES			0x18
+#define QCA956X_GMAC_REG_MR_AN_CTRL			0x1c
+#define QCA956X_GMAC_REG_SGMII_CONFIG			0x34
+#define QCA956X_GMAC_REG_SGMII_DEBUG			0x58
+
+#define QCA956X_ETH_CFG_GE0_SGMII			BIT(6)
+
 #endif /* __ASM_AR71XX_H */
diff --git a/arch/mips/mach-ath79/include/mach/ath79.h b/arch/mips/mach-ath79/include/mach/ath79.h
index 5de7a43f79..0fde5079b1 100644
--- a/arch/mips/mach-ath79/include/mach/ath79.h
+++ b/arch/mips/mach-ath79/include/mach/ath79.h
@@ -2,6 +2,7 @@
 /*
  * Atheros AR71XX/AR724X/AR913X common definitions
  *
+ * Copyright (C) 2018-2019 Rosy Song <rosysong@rosinson.com>
  * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
  * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
  * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
@@ -146,4 +147,6 @@ int ath79_usb_reset(void);
 void ar934x_pll_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz);
 void ar934x_ddr_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz);
 
+void qca956x_pll_init(void);
+void qca956x_ddr_init(void);
 #endif /* __ASM_MACH_ATH79_H */
diff --git a/arch/mips/mach-ath79/qca956x/Makefile b/arch/mips/mach-ath79/qca956x/Makefile
new file mode 100644
index 0000000000..3f5fc0363f
--- /dev/null
+++ b/arch/mips/mach-ath79/qca956x/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += cpu.o
+obj-y += clk.o
+obj-y += ddr.o qca956x-ddr-tap.o
diff --git a/arch/mips/mach-ath79/qca956x/clk.c b/arch/mips/mach-ath79/qca956x/clk.c
new file mode 100644
index 0000000000..ca956d1291
--- /dev/null
+++ b/arch/mips/mach-ath79/qca956x/clk.c
@@ -0,0 +1,419 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Rosy Song <rosysong@rosinson.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/ath79.h>
+#include <wait_bit.h>
+
+#define PLL_SRIF_DPLL2_KI_LSB 29
+#define PLL_SRIF_DPLL2_KI_MASK 0x60000000
+#define PLL_SRIF_DPLL2_KI_SET(x) \
+	(((x) << PLL_SRIF_DPLL2_KI_LSB) & PLL_SRIF_DPLL2_KI_MASK)
+#define PLL_SRIF_DPLL2_KD_LSB 25
+#define PLL_SRIF_DPLL2_KD_MASK 0x1e000000
+#define PLL_SRIF_DPLL2_KD_SET(x) \
+	(((x) << PLL_SRIF_DPLL2_KD_LSB) & PLL_SRIF_DPLL2_KD_MASK)
+#define PLL_SRIF_DPLL2_PLL_PWD_LSB 22
+#define PLL_SRIF_DPLL2_PLL_PWD_MASK 0x00400000
+#define PLL_SRIF_DPLL2_PLL_PWD_SET(x) \
+	(((x) << PLL_SRIF_DPLL2_PLL_PWD_LSB) & PLL_SRIF_DPLL2_PLL_PWD_MASK)
+#define PLL_SRIF_DPLL2_OUTDIV_LSB 19
+#define PLL_SRIF_DPLL2_OUTDIV_MASK 0x00380000
+#define PLL_SRIF_DPLL2_OUTDIV_SET(x) \
+	(((x) << PLL_SRIF_DPLL2_OUTDIV_LSB) & PLL_SRIF_DPLL2_OUTDIV_MASK)
+#define PLL_SRIF_DPLL2_PHASE_SHIFT_LSB 12
+#define PLL_SRIF_DPLL2_PHASE_SHIFT_MASK 0x0007f000
+#define PLL_SRIF_DPLL2_PHASE_SHIFT_SET(x) \
+	(((x) << PLL_SRIF_DPLL2_PHASE_SHIFT_LSB) & PLL_SRIF_DPLL2_PHASE_SHIFT_MASK)
+#define CPU_PLL_CONFIG_PLLPWD_LSB 30
+#define CPU_PLL_CONFIG_PLLPWD_MASK 0x40000000
+#define CPU_PLL_CONFIG_PLLPWD_SET(x) \
+	(((x) << CPU_PLL_CONFIG_PLLPWD_LSB) & CPU_PLL_CONFIG_PLLPWD_MASK)
+#define CPU_PLL_CONFIG_OUTDIV_LSB 19
+#define CPU_PLL_CONFIG_OUTDIV_MASK 0x00380000
+#define CPU_PLL_CONFIG_OUTDIV_SET(x) \
+	(((x) << CPU_PLL_CONFIG_OUTDIV_LSB) & CPU_PLL_CONFIG_OUTDIV_MASK)
+#define CPU_PLL_CONFIG_RANGE_LSB 17
+#define CPU_PLL_CONFIG_RANGE_MASK 0x00060000
+#define CPU_PLL_CONFIG_RANGE_SET(x) \
+	(((x) << CPU_PLL_CONFIG_RANGE_LSB) & CPU_PLL_CONFIG_RANGE_MASK)
+#define CPU_PLL_CONFIG_REFDIV_LSB 12
+#define CPU_PLL_CONFIG_REFDIV_MASK 0x0001f000
+#define CPU_PLL_CONFIG_REFDIV_SET(x) \
+	(((x) << CPU_PLL_CONFIG_REFDIV_LSB) & CPU_PLL_CONFIG_REFDIV_MASK)
+#define CPU_PLL_CONFIG1_NINT_LSB 18
+#define CPU_PLL_CONFIG1_NINT_MASK 0x07fc0000
+#define CPU_PLL_CONFIG1_NINT_SET(x) \
+	(((x) << CPU_PLL_CONFIG1_NINT_LSB) & CPU_PLL_CONFIG1_NINT_MASK)
+#define CPU_PLL_DITHER1_DITHER_EN_LSB 31
+#define CPU_PLL_DITHER1_DITHER_EN_MASK 0x80000000
+#define CPU_PLL_DITHER1_DITHER_EN_SET(x) \
+	(((x) << CPU_PLL_DITHER1_DITHER_EN_LSB) & CPU_PLL_DITHER1_DITHER_EN_MASK)
+#define CPU_PLL_DITHER1_UPDATE_COUNT_LSB 24
+#define CPU_PLL_DITHER1_UPDATE_COUNT_MASK 0x3f000000
+#define CPU_PLL_DITHER1_UPDATE_COUNT_SET(x) \
+	(((x) << CPU_PLL_DITHER1_UPDATE_COUNT_LSB) & CPU_PLL_DITHER1_UPDATE_COUNT_MASK)
+#define CPU_PLL_DITHER1_NFRAC_STEP_LSB 18
+#define CPU_PLL_DITHER1_NFRAC_STEP_MASK 0x00fc0000
+#define CPU_PLL_DITHER1_NFRAC_STEP_SET(x) \
+	(((x) << CPU_PLL_DITHER1_NFRAC_STEP_LSB) & CPU_PLL_DITHER1_NFRAC_STEP_MASK)
+#define CPU_PLL_DITHER1_NFRAC_MIN_LSB 0
+#define CPU_PLL_DITHER1_NFRAC_MIN_MASK 0x0003ffff
+#define CPU_PLL_DITHER1_NFRAC_MIN_SET(x) \
+	(((x) << CPU_PLL_DITHER1_NFRAC_MIN_LSB) & CPU_PLL_DITHER1_NFRAC_MIN_MASK)
+#define CPU_PLL_DITHER2_NFRAC_MAX_LSB 0
+#define CPU_PLL_DITHER2_NFRAC_MAX_MASK 0x0003ffff
+#define CPU_PLL_DITHER2_NFRAC_MAX_SET(x) \
+	(((x) << CPU_PLL_DITHER2_NFRAC_MAX_LSB) & CPU_PLL_DITHER2_NFRAC_MAX_MASK)
+#define DDR_PLL_CONFIG_PLLPWD_LSB 30
+#define DDR_PLL_CONFIG_PLLPWD_MASK 0x40000000
+#define DDR_PLL_CONFIG_PLLPWD_SET(x) \
+	(((x) << DDR_PLL_CONFIG_PLLPWD_LSB) & DDR_PLL_CONFIG_PLLPWD_MASK)
+#define DDR_PLL_CONFIG_OUTDIV_LSB 23
+#define DDR_PLL_CONFIG_OUTDIV_MASK 0x03800000
+#define DDR_PLL_CONFIG_OUTDIV_SET(x) \
+	(((x) << DDR_PLL_CONFIG_OUTDIV_LSB) & DDR_PLL_CONFIG_OUTDIV_MASK)
+#define DDR_PLL_CONFIG_RANGE_LSB 21
+#define DDR_PLL_CONFIG_RANGE_MASK 0x00600000
+#define DDR_PLL_CONFIG_RANGE_SET(x) \
+	(((x) << DDR_PLL_CONFIG_RANGE_LSB) & DDR_PLL_CONFIG_RANGE_MASK)
+#define DDR_PLL_CONFIG_REFDIV_LSB 16
+#define DDR_PLL_CONFIG_REFDIV_MASK 0x001f0000
+#define DDR_PLL_CONFIG_REFDIV_SET(x) \
+	(((x) << DDR_PLL_CONFIG_REFDIV_LSB) & DDR_PLL_CONFIG_REFDIV_MASK)
+#define DDR_PLL_CONFIG1_NINT_LSB 18
+#define DDR_PLL_CONFIG1_NINT_MASK 0x07fc0000
+#define DDR_PLL_CONFIG1_NINT_SET(x) \
+	(((x) << DDR_PLL_CONFIG1_NINT_LSB) & DDR_PLL_CONFIG1_NINT_MASK)
+#define DDR_PLL_DITHER1_DITHER_EN_LSB 31
+#define DDR_PLL_DITHER1_DITHER_EN_MASK 0x80000000
+#define DDR_PLL_DITHER1_DITHER_EN_SET(x) \
+	(((x) << DDR_PLL_DITHER1_DITHER_EN_LSB) & DDR_PLL_DITHER1_DITHER_EN_MASK)
+#define DDR_PLL_DITHER1_UPDATE_COUNT_LSB 27
+#define DDR_PLL_DITHER1_UPDATE_COUNT_MASK 0x78000000
+#define DDR_PLL_DITHER1_UPDATE_COUNT_SET(x) \
+	(((x) << DDR_PLL_DITHER1_UPDATE_COUNT_LSB) & DDR_PLL_DITHER1_UPDATE_COUNT_MASK)
+#define DDR_PLL_DITHER1_NFRAC_STEP_LSB 20
+#define DDR_PLL_DITHER1_NFRAC_STEP_MASK 0x07f00000
+#define DDR_PLL_DITHER1_NFRAC_STEP_SET(x) \
+	(((x) << DDR_PLL_DITHER1_NFRAC_STEP_LSB) & DDR_PLL_DITHER1_NFRAC_STEP_MASK)
+#define DDR_PLL_DITHER1_NFRAC_MIN_LSB 0
+#define DDR_PLL_DITHER1_NFRAC_MIN_MASK 0x0003ffff
+#define DDR_PLL_DITHER1_NFRAC_MIN_SET(x) \
+	(((x) << DDR_PLL_DITHER1_NFRAC_MIN_LSB) & DDR_PLL_DITHER1_NFRAC_MIN_MASK)
+#define DDR_PLL_DITHER2_NFRAC_MAX_LSB 0
+#define DDR_PLL_DITHER2_NFRAC_MAX_MASK 0x0003ffff
+#define DDR_PLL_DITHER2_NFRAC_MAX_SET(x) \
+	(((x) << DDR_PLL_DITHER2_NFRAC_MAX_LSB) & DDR_PLL_DITHER2_NFRAC_MAX_MASK)
+#define CPU_DDR_CLOCK_CONTROL_AHBCLK_FROM_DDRPLL_LSB 24
+#define CPU_DDR_CLOCK_CONTROL_AHBCLK_FROM_DDRPLL_MASK 0x01000000
+#define CPU_DDR_CLOCK_CONTROL_AHBCLK_FROM_DDRPLL_SET(x) \
+	(((x) << CPU_DDR_CLOCK_CONTROL_AHBCLK_FROM_DDRPLL_LSB) & CPU_DDR_CLOCK_CONTROL_AHBCLK_FROM_DDRPLL_MASK)
+#define CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_CPUPLL_LSB 21
+#define CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_CPUPLL_MASK 0x00200000
+#define CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_CPUPLL_SET(x) \
+	(((x) << CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_CPUPLL_LSB) & CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_CPUPLL_MASK)
+#define CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_DDRPLL_LSB 20
+#define CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_DDRPLL_MASK 0x00100000
+#define CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_DDRPLL_SET(x) \
+	(((x) << CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_DDRPLL_LSB) & CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_DDRPLL_MASK)
+#define CPU_DDR_CLOCK_CONTROL_AHB_POST_DIV_LSB 15
+#define CPU_DDR_CLOCK_CONTROL_AHB_POST_DIV_MASK 0x000f8000
+#define CPU_DDR_CLOCK_CONTROL_AHB_POST_DIV_SET(x) \
+	(((x) << CPU_DDR_CLOCK_CONTROL_AHB_POST_DIV_LSB) & CPU_DDR_CLOCK_CONTROL_AHB_POST_DIV_MASK)
+#define CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV_LSB 10
+#define CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV_MASK 0x00007c00
+#define CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV_SET(x) \
+	(((x) << CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV_LSB) & CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV_MASK)
+#define CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV_LSB 5
+#define CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV_MASK 0x000003e0
+#define CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV_SET(x) \
+	(((x) << CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV_LSB) & CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV_MASK)
+#define CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_LSB 4
+#define CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_MASK 0x00000010
+#define CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_SET(x) \
+	(((x) << CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_LSB) & CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_MASK)
+#define CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_LSB 3
+#define CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_MASK 0x00000008
+#define CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_SET(x) \
+	(((x) << CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_LSB) & CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_MASK)
+#define CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_LSB 2
+#define CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_MASK 0x00000004
+#define CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_SET(x) \
+	(((x) << CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_LSB) & CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_MASK)
+
+#define CPU_PLL_CONFIG1_NINT_VAL CPU_PLL_CONFIG1_NINT_SET(0x1f)
+#define CPU_PLL_CONFIG_REF_DIV_VAL CPU_PLL_CONFIG_REFDIV_SET(0x1)
+#define CPU_PLL_CONFIG_RANGE_VAL CPU_PLL_CONFIG_RANGE_SET(0)
+#define CPU_PLL_CONFIG_OUT_DIV_VAL1 CPU_PLL_CONFIG_OUTDIV_SET(0)
+#define CPU_PLL_CONFIG_OUT_DIV_VAL2 CPU_PLL_CONFIG_OUTDIV_SET(0)
+#define CPU_PLL_DITHER1_VAL CPU_PLL_DITHER1_DITHER_EN_SET(0) | \
+	CPU_PLL_DITHER1_NFRAC_MIN_SET(0) | \
+	CPU_PLL_DITHER1_NFRAC_STEP_SET(0) | \
+	CPU_PLL_DITHER1_UPDATE_COUNT_SET(0x0)
+#define CPU_PLL_DITHER2_VAL CPU_PLL_DITHER2_NFRAC_MAX_SET(0x0)
+#define DDR_PLL_CONFIG1_NINT_VAL DDR_PLL_CONFIG1_NINT_SET(0x1a)
+#define DDR_PLL_CONFIG_REF_DIV_VAL DDR_PLL_CONFIG_REFDIV_SET(0x1)
+#define DDR_PLL_CONFIG_RANGE_VAL DDR_PLL_CONFIG_RANGE_SET(0)
+#define DDR_PLL_CONFIG_OUT_DIV_VAL1 DDR_PLL_CONFIG_OUTDIV_SET(0)
+#define DDR_PLL_CONFIG_OUT_DIV_VAL2 DDR_PLL_CONFIG_OUTDIV_SET(0)
+#define DDR_PLL_DITHER1_VAL DDR_PLL_DITHER1_DITHER_EN_SET(0) | \
+	DDR_PLL_DITHER1_NFRAC_MIN_SET(0) | \
+	DDR_PLL_DITHER1_NFRAC_STEP_SET(0) | \
+	DDR_PLL_DITHER1_UPDATE_COUNT_SET(0x0)
+#define DDR_PLL_DITHER2_VAL DDR_PLL_DITHER2_NFRAC_MAX_SET(0x0)
+#define AHB_CLK_FROM_DDR CPU_DDR_CLOCK_CONTROL_AHBCLK_FROM_DDRPLL_SET(0)
+#define CPU_AND_DDR_CLK_FROM_DDR \
+	CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_DDRPLL_SET(0)
+#define CPU_AND_DDR_CLK_FROM_CPU \
+	CPU_DDR_CLOCK_CONTROL_CPU_DDR_CLK_FROM_CPUPLL_SET(0)
+#define CPU_DDR_CLOCK_CONTROL_AHB_DIV_VAL \
+	CPU_DDR_CLOCK_CONTROL_AHB_POST_DIV_SET(0x2)
+#define CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV \
+	CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV_SET(0)
+#define CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV \
+	CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV_SET(0)
+
+static inline void set_val(u32 _reg, u32 _mask, u32 _val)
+{
+	void __iomem *pll_regs = map_physmem(AR71XX_PLL_BASE,
+					     AR71XX_PLL_SIZE, MAP_NOCACHE);
+	writel((readl(pll_regs + _reg) & (~(_mask))) | _val, pll_regs + _reg);
+}
+
+#define cpu_pll_set(_mask, _val)	\
+	set_val(QCA956X_PLL_CPU_CONFIG_REG, _mask, _val)
+
+#define ddr_pll_set(_mask, _val)	\
+	set_val(QCA956X_PLL_DDR_CONFIG_REG, _mask, _val)
+
+#define cpu_ddr_control_set(_mask, _val)	\
+	set_val(QCA956X_PLL_CLK_CTRL_REG, _mask, _val)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u32 qca956x_get_xtal(void)
+{
+	u32 val;
+
+	val = ath79_get_bootstrap();
+	if (val & QCA956X_BOOTSTRAP_REF_CLK_40)
+		return 40000000;
+	else
+		return 25000000;
+}
+
+int get_serial_clock(void)
+{
+	return qca956x_get_xtal();
+}
+
+void qca956x_pll_init(void)
+{
+	void __iomem *srif_regs = map_physmem(QCA956X_SRIF_BASE,
+					      QCA956X_SRIF_SIZE, MAP_NOCACHE);
+	void __iomem *pll_regs = map_physmem(AR71XX_PLL_BASE,
+					     AR71XX_PLL_SIZE, MAP_NOCACHE);
+
+	/* 8.16.2 Baseband DPLL2 */
+	writel(PLL_SRIF_DPLL2_KI_SET(2) | PLL_SRIF_DPLL2_KD_SET(0xa) |
+		PLL_SRIF_DPLL2_PLL_PWD_SET(1) | PLL_SRIF_DPLL2_OUTDIV_SET(1) |
+		PLL_SRIF_DPLL2_PHASE_SHIFT_SET(6), srif_regs + QCA956X_SRIF_BB_DPLL2_REG);
+
+	/* 8.16.2 PCIE DPLL2 */
+	writel(PLL_SRIF_DPLL2_KI_SET(2) | PLL_SRIF_DPLL2_KD_SET(0xa) |
+		PLL_SRIF_DPLL2_PLL_PWD_SET(1) | PLL_SRIF_DPLL2_OUTDIV_SET(3) |
+		PLL_SRIF_DPLL2_PHASE_SHIFT_SET(6), srif_regs + QCA956X_SRIF_PCIE_DPLL2_REG);
+
+	/* 8.16.2 DDR DPLL2 */
+	writel(PLL_SRIF_DPLL2_KI_SET(2) | PLL_SRIF_DPLL2_KD_SET(0xa) |
+		PLL_SRIF_DPLL2_PLL_PWD_SET(1) | PLL_SRIF_DPLL2_PHASE_SHIFT_SET(6),
+		srif_regs + QCA956X_SRIF_DDR_DPLL2_REG);
+
+	/* 8.16.2 CPU DPLL2 */
+	writel(PLL_SRIF_DPLL2_KI_SET(1) | PLL_SRIF_DPLL2_KD_SET(7) |
+			  PLL_SRIF_DPLL2_PLL_PWD_SET(1) | PLL_SRIF_DPLL2_PHASE_SHIFT_SET(6),
+			  srif_regs + QCA956X_SRIF_CPU_DPLL2_REG);
+
+	/* pll_bypass_set */
+	cpu_ddr_control_set(CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_MASK,
+			   CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_SET(1));
+	cpu_ddr_control_set(CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_MASK,
+			   CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_SET(1));
+	cpu_ddr_control_set(CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_MASK,
+			   CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_SET(1));
+
+	/* init_cpu_pll */
+	cpu_pll_set(CPU_PLL_CONFIG_PLLPWD_MASK,  CPU_PLL_CONFIG_PLLPWD_SET(1));
+	cpu_pll_set(CPU_PLL_CONFIG_REFDIV_MASK, CPU_PLL_CONFIG_REF_DIV_VAL);
+	cpu_pll_set(CPU_PLL_CONFIG_RANGE_MASK, CPU_PLL_CONFIG_RANGE_VAL);
+	cpu_pll_set(CPU_PLL_CONFIG_OUTDIV_MASK, CPU_PLL_CONFIG_OUT_DIV_VAL1);
+	set_val(QCA956X_PLL_CPU_CONFIG1_REG, CPU_PLL_CONFIG1_NINT_MASK, \
+		CPU_PLL_CONFIG1_NINT_VAL);
+
+	/* init_ddr_pll */
+	ddr_pll_set(DDR_PLL_CONFIG_PLLPWD_MASK,  DDR_PLL_CONFIG_PLLPWD_SET(1));
+	ddr_pll_set(DDR_PLL_CONFIG_REFDIV_MASK, DDR_PLL_CONFIG_REF_DIV_VAL);
+	ddr_pll_set(DDR_PLL_CONFIG_RANGE_MASK, DDR_PLL_CONFIG_RANGE_VAL);
+	ddr_pll_set(DDR_PLL_CONFIG_OUTDIV_MASK, DDR_PLL_CONFIG_OUT_DIV_VAL1);
+	set_val(QCA956X_PLL_DDR_CONFIG1_REG, DDR_PLL_CONFIG1_NINT_MASK,
+		DDR_PLL_CONFIG1_NINT_VAL);
+
+	/* init_ahb_pll */
+	writel(CPU_DDR_CLOCK_CONTROL_AHB_DIV_VAL | AHB_CLK_FROM_DDR |
+		CPU_AND_DDR_CLK_FROM_DDR | CPU_AND_DDR_CLK_FROM_CPU |
+		CPU_DDR_CLOCK_CONTROL_DDR_POST_DIV | CPU_DDR_CLOCK_CONTROL_CPU_POST_DIV |
+		CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_SET(1) |
+		CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_SET(1) |
+		CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_SET(1), pll_regs + QCA956X_PLL_CLK_CTRL_REG);
+
+	/* ddr_pll_dither_unset */
+	writel(DDR_PLL_DITHER1_VAL, pll_regs + QCA956X_PLL_DDR_DIT_FRAC_REG);
+	writel(DDR_PLL_DITHER2_VAL, pll_regs + QCA956X_PLL_DDR_DIT2_FRAC_REG);
+
+	/* cpu_pll_dither_unset */
+	writel(CPU_PLL_DITHER1_VAL, pll_regs + QCA956X_PLL_CPU_DIT_FRAC_REG);
+	writel(CPU_PLL_DITHER2_VAL, pll_regs + QCA956X_PLL_CPU_DIT2_FRAC_REG);
+
+	/* pll_pwd_unset */
+	cpu_pll_set(CPU_PLL_CONFIG_PLLPWD_MASK, CPU_PLL_CONFIG_PLLPWD_SET(0));
+	ddr_pll_set(DDR_PLL_CONFIG_PLLPWD_MASK, DDR_PLL_CONFIG_PLLPWD_SET(0));
+
+	/* outdiv_unset */
+	cpu_pll_set(CPU_PLL_CONFIG_OUTDIV_MASK, CPU_PLL_CONFIG_OUT_DIV_VAL2);
+	ddr_pll_set(DDR_PLL_CONFIG_OUTDIV_MASK, DDR_PLL_CONFIG_OUT_DIV_VAL2);
+
+	/* pll_bypass_unset */
+	cpu_ddr_control_set(CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_MASK,
+			   CPU_DDR_CLOCK_CONTROL_CPU_PLL_BYPASS_SET(0));
+	cpu_ddr_control_set(CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_MASK,
+			   CPU_DDR_CLOCK_CONTROL_DDR_PLL_BYPASS_SET(0));
+	cpu_ddr_control_set(CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_MASK,
+			   CPU_DDR_CLOCK_CONTROL_AHB_PLL_BYPASS_SET(0));
+
+	while (readl(pll_regs + QCA956X_PLL_CPU_CONFIG_REG) & 0x8000000)
+		/* NOP */;
+
+	while (readl(pll_regs + QCA956X_PLL_DDR_CONFIG_REG) & 0x8000000)
+		/* NOP */;
+}
+
+int get_clocks(void)
+{
+	void __iomem *regs;
+	u32 ref_rate, cpu_rate, ddr_rate, ahb_rate;
+	u32 out_div, ref_div, postdiv, nint, hfrac, lfrac, clk_ctrl;
+	u32 pll, cpu_pll, ddr_pll, misc;
+
+	/*
+	 * QCA956x timer init workaround has to be applied right before setting
+	 * up the clock. Else, there will be no jiffies
+	 */
+	regs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+			  MAP_NOCACHE);
+	misc = readl(regs + AR71XX_RESET_REG_MISC_INT_ENABLE);
+	misc |= MISC_INT_MIPS_SI_TIMERINT_MASK;
+	writel(misc, regs + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+	regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+			  MAP_NOCACHE);
+	pll = readl(regs + QCA956X_PLL_CPU_CONFIG_REG);
+	out_div = (pll >> QCA956X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
+			  QCA956X_PLL_CPU_CONFIG_OUTDIV_MASK;
+	ref_div = (pll >> QCA956X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
+			  QCA956X_PLL_CPU_CONFIG_REFDIV_MASK;
+
+	pll = readl(regs + QCA956X_PLL_CPU_CONFIG1_REG);
+	nint = (pll >> QCA956X_PLL_CPU_CONFIG1_NINT_SHIFT) &
+			  QCA956X_PLL_CPU_CONFIG1_NINT_MASK;
+	hfrac = (pll >> QCA956X_PLL_CPU_CONFIG1_NFRAC_H_SHIFT) &
+			  QCA956X_PLL_CPU_CONFIG1_NFRAC_H_MASK;
+	lfrac = (pll >> QCA956X_PLL_CPU_CONFIG1_NFRAC_L_SHIFT) &
+			  QCA956X_PLL_CPU_CONFIG1_NFRAC_L_MASK;
+
+	ref_rate = qca956x_get_xtal();
+
+	cpu_pll = nint * ref_rate / ref_div;
+	cpu_pll += (lfrac * ref_rate) / ((ref_div * 25) << 13);
+	cpu_pll += (hfrac >> 13) * ref_rate / ref_div;
+	cpu_pll /= (1 << out_div);
+
+	pll = readl(regs + QCA956X_PLL_DDR_CONFIG_REG);
+	out_div = (pll >> QCA956X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
+			  QCA956X_PLL_DDR_CONFIG_OUTDIV_MASK;
+	ref_div = (pll >> QCA956X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
+			  QCA956X_PLL_DDR_CONFIG_REFDIV_MASK;
+	pll = readl(regs + QCA956X_PLL_DDR_CONFIG1_REG);
+	nint = (pll >> QCA956X_PLL_DDR_CONFIG1_NINT_SHIFT) &
+		QCA956X_PLL_DDR_CONFIG1_NINT_MASK;
+	hfrac = (pll >> QCA956X_PLL_DDR_CONFIG1_NFRAC_H_SHIFT) &
+		QCA956X_PLL_DDR_CONFIG1_NFRAC_H_MASK;
+	lfrac = (pll >> QCA956X_PLL_DDR_CONFIG1_NFRAC_L_SHIFT) &
+		QCA956X_PLL_DDR_CONFIG1_NFRAC_L_MASK;
+
+	ddr_pll = nint * ref_rate / ref_div;
+	ddr_pll += (lfrac * ref_rate) / ((ref_div * 25) << 13);
+	ddr_pll += (hfrac >> 13) * ref_rate / ref_div;
+	ddr_pll /= (1 << out_div);
+
+	clk_ctrl = readl(regs + QCA956X_PLL_CLK_CTRL_REG);
+
+	postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
+		  QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
+
+	if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
+		cpu_rate = ref_rate;
+	else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_CPUPLL)
+		cpu_rate = ddr_pll / (postdiv + 1);
+	else
+		cpu_rate = cpu_pll / (postdiv + 1);
+
+	postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
+		  QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
+
+	if (clk_ctrl & QCA956X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
+		ddr_rate = ref_rate;
+	else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_DDRPLL)
+		ddr_rate = cpu_pll / (postdiv + 1);
+	else
+		ddr_rate = ddr_pll / (postdiv + 1);
+
+	postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
+		  QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
+
+	if (clk_ctrl & QCA956X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
+		ahb_rate = ref_rate;
+	else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
+		ahb_rate = ddr_pll / (postdiv + 1);
+	else
+		ahb_rate = cpu_pll / (postdiv + 1);
+
+	gd->cpu_clk = cpu_rate;
+	gd->mem_clk = ddr_rate;
+	gd->bus_clk = ahb_rate;
+
+	debug("cpu_clk=%u, ddr_clk=%u, bus_clk=%u\n",
+		cpu_rate, ddr_rate, ahb_rate);
+
+	return 0;
+}
+
+ulong get_bus_freq(ulong dummy)
+{
+	if (!gd->bus_clk)
+		get_clocks();
+	return gd->bus_clk;
+}
+
+ulong get_ddr_freq(ulong dummy)
+{
+	if (!gd->mem_clk)
+		get_clocks();
+	return gd->mem_clk;
+}
diff --git a/arch/mips/mach-ath79/qca956x/cpu.c b/arch/mips/mach-ath79/qca956x/cpu.c
new file mode 100644
index 0000000000..08a8c84e72
--- /dev/null
+++ b/arch/mips/mach-ath79/qca956x/cpu.c
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Rosy Song <rosysong@rosinson.com>
+ */
+
+#include <common.h>
+
+/* The lowlevel_init() is not needed on QCA956X */
+void lowlevel_init(void) {}
diff --git a/arch/mips/mach-ath79/qca956x/ddr.c b/arch/mips/mach-ath79/qca956x/ddr.c
new file mode 100644
index 0000000000..fb2230430c
--- /dev/null
+++ b/arch/mips/mach-ath79/qca956x/ddr.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Rosy Song <rosysong@rosinson.com>
+ *
+ * Based on QSDK
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/ath79.h>
+
+#define DDR_FSM_WAIT_CTRL_VAL 0xa12
+#define DDR_CTL_CONFIG_SRAM_TSEL_LSB 30
+#define DDR_CTL_CONFIG_SRAM_TSEL_MASK 0xc0000000
+#define DDR_CTL_CONFIG_SRAM_TSEL_SET(x) \
+	(((x) << DDR_CTL_CONFIG_SRAM_TSEL_LSB) & DDR_CTL_CONFIG_SRAM_TSEL_MASK)
+#define DDR_CTL_CONFIG_GE0_SRAM_SYNC_LSB 20
+#define DDR_CTL_CONFIG_GE0_SRAM_SYNC_MASK 0x00100000
+#define DDR_CTL_CONFIG_GE0_SRAM_SYNC_SET(x) \
+	(((x) << DDR_CTL_CONFIG_GE0_SRAM_SYNC_LSB) & DDR_CTL_CONFIG_GE0_SRAM_SYNC_MASK)
+#define DDR_CTL_CONFIG_GE1_SRAM_SYNC_LSB 19
+#define DDR_CTL_CONFIG_GE1_SRAM_SYNC_MASK 0x00080000
+#define DDR_CTL_CONFIG_GE1_SRAM_SYNC_SET(x) \
+	(((x) << DDR_CTL_CONFIG_GE1_SRAM_SYNC_LSB) & DDR_CTL_CONFIG_GE1_SRAM_SYNC_MASK)
+#define DDR_CTL_CONFIG_USB_SRAM_SYNC_LSB 18
+#define DDR_CTL_CONFIG_USB_SRAM_SYNC_MASK 0x00040000
+#define DDR_CTL_CONFIG_USB_SRAM_SYNC_SET(x) \
+	(((x) << DDR_CTL_CONFIG_USB_SRAM_SYNC_LSB) & DDR_CTL_CONFIG_USB_SRAM_SYNC_MASK)
+#define DDR_CTL_CONFIG_PCIE_SRAM_SYNC_LSB 17
+#define DDR_CTL_CONFIG_PCIE_SRAM_SYNC_MASK 0x00020000
+#define DDR_CTL_CONFIG_PCIE_SRAM_SYNC_SET(x) \
+	(((x) << DDR_CTL_CONFIG_PCIE_SRAM_SYNC_LSB) & DDR_CTL_CONFIG_PCIE_SRAM_SYNC_MASK)
+#define DDR_CTL_CONFIG_WMAC_SRAM_SYNC_LSB 16
+#define DDR_CTL_CONFIG_WMAC_SRAM_SYNC_MASK 0x00010000
+#define DDR_CTL_CONFIG_WMAC_SRAM_SYNC_SET(x) \
+	(((x) << DDR_CTL_CONFIG_WMAC_SRAM_SYNC_LSB) & DDR_CTL_CONFIG_WMAC_SRAM_SYNC_MASK)
+#define DDR_CTL_CONFIG_MISC_SRC1_SRAM_SYNC_LSB 15
+#define DDR_CTL_CONFIG_MISC_SRC1_SRAM_SYNC_MASK 0x00008000
+#define DDR_CTL_CONFIG_MISC_SRC1_SRAM_SYNC_SET(x) \
+	(((x) << DDR_CTL_CONFIG_MISC_SRC1_SRAM_SYNC_LSB) & DDR_CTL_CONFIG_MISC_SRC1_SRAM_SYNC_MASK)
+#define DDR_CTL_CONFIG_MISC_SRC2_SRAM_SYNC_LSB 14
+#define DDR_CTL_CONFIG_MISC_SRC2_SRAM_SYNC_MASK 0x00004000
+#define DDR_CTL_CONFIG_MISC_SRC2_SRAM_SYNC_SET(x) \
+	(((x) << DDR_CTL_CONFIG_MISC_SRC2_SRAM_SYNC_LSB) & DDR_CTL_CONFIG_MISC_SRC2_SRAM_SYNC_MASK)
+#define DDR_CTL_CONFIG_PAD_DDR2_SEL_LSB 6
+#define DDR_CTL_CONFIG_PAD_DDR2_SEL_MASK 0x00000040
+#define DDR_CTL_CONFIG_PAD_DDR2_SEL_SET(x) \
+	(((x) << DDR_CTL_CONFIG_PAD_DDR2_SEL_LSB) & DDR_CTL_CONFIG_PAD_DDR2_SEL_MASK)
+#define DDR_CTL_CONFIG_CPU_DDR_SYNC_LSB 2
+#define DDR_CTL_CONFIG_CPU_DDR_SYNC_MASK 0x00000004
+#define DDR_CTL_CONFIG_CPU_DDR_SYNC_SET(x) \
+	(((x) << DDR_CTL_CONFIG_CPU_DDR_SYNC_LSB) & DDR_CTL_CONFIG_CPU_DDR_SYNC_MASK)
+#define DDR_CTL_CONFIG_HALF_WIDTH_LSB 1
+#define DDR_CTL_CONFIG_HALF_WIDTH_MASK 0x00000002
+#define DDR_CTL_CONFIG_HALF_WIDTH_SET(x) \
+	(((x) << DDR_CTL_CONFIG_HALF_WIDTH_LSB) & DDR_CTL_CONFIG_HALF_WIDTH_MASK)
+#define DDR_CONFIG_CAS_LATENCY_MSB_LSB 31
+#define DDR_CONFIG_CAS_LATENCY_MSB_MASK 0x80000000
+#define DDR_CONFIG_CAS_LATENCY_MSB_SET(x) \
+	(((x) << DDR_CONFIG_CAS_LATENCY_MSB_LSB) & DDR_CONFIG_CAS_LATENCY_MSB_MASK)
+#define DDR_CONFIG_OPEN_PAGE_LSB 30
+#define DDR_CONFIG_OPEN_PAGE_MASK 0x40000000
+#define DDR_CONFIG_OPEN_PAGE_SET(x) \
+	(((x) << DDR_CONFIG_OPEN_PAGE_LSB) & DDR_CONFIG_OPEN_PAGE_MASK)
+#define DDR_CONFIG_CAS_LATENCY_LSB 27
+#define DDR_CONFIG_CAS_LATENCY_MASK 0x38000000
+#define DDR_CONFIG_CAS_LATENCY_SET(x) \
+	(((x) << DDR_CONFIG_CAS_LATENCY_LSB) & DDR_CONFIG_CAS_LATENCY_MASK)
+#define DDR_CONFIG_TMRD_LSB 23
+#define DDR_CONFIG_TMRD_MASK 0x07800000
+#define DDR_CONFIG_TMRD_SET(x) \
+	(((x) << DDR_CONFIG_TMRD_LSB) & DDR_CONFIG_TMRD_MASK)
+#define DDR_CONFIG_TRFC_LSB 17
+#define DDR_CONFIG_TRFC_MASK 0x007e0000
+#define DDR_CONFIG_TRFC_SET(x) \
+	(((x) << DDR_CONFIG_TRFC_LSB) & DDR_CONFIG_TRFC_MASK)
+#define DDR_CONFIG_TRRD_LSB 13
+#define DDR_CONFIG_TRRD_MASK 0x0001e000
+#define DDR_CONFIG_TRRD_SET(x) \
+	(((x) << DDR_CONFIG_TRRD_LSB) & DDR_CONFIG_TRRD_MASK)
+#define DDR_CONFIG_TRP_LSB 9
+#define DDR_CONFIG_TRP_MASK 0x00001e00
+#define DDR_CONFIG_TRP_SET(x) \
+	(((x) << DDR_CONFIG_TRP_LSB) & DDR_CONFIG_TRP_MASK)
+#define DDR_CONFIG_TRCD_LSB 5
+#define DDR_CONFIG_TRCD_MASK 0x000001e0
+#define DDR_CONFIG_TRCD_SET(x) \
+	(((x) << DDR_CONFIG_TRCD_LSB) & DDR_CONFIG_TRCD_MASK)
+#define DDR_CONFIG_TRAS_LSB 0
+#define DDR_CONFIG_TRAS_MASK 0x0000001f
+#define DDR_CONFIG_TRAS_SET(x) \
+	(((x) << DDR_CONFIG_TRAS_LSB) & DDR_CONFIG_TRAS_MASK)
+#define DDR_CONFIG2_HALF_WIDTH_LOW_LSB 31
+#define DDR_CONFIG2_HALF_WIDTH_LOW_MASK 0x80000000
+#define DDR_CONFIG2_HALF_WIDTH_LOW_SET(x) \
+	(((x) << DDR_CONFIG2_HALF_WIDTH_LOW_LSB) & DDR_CONFIG2_HALF_WIDTH_LOW_MASK)
+#define DDR_CONFIG2_SWAP_A26_A27_LSB 30
+#define DDR_CONFIG2_SWAP_A26_A27_MASK 0x40000000
+#define DDR_CONFIG2_SWAP_A26_A27_SET(x) \
+	(((x) << DDR_CONFIG2_SWAP_A26_A27_LSB) & DDR_CONFIG2_SWAP_A26_A27_MASK)
+#define DDR_CONFIG2_GATE_OPEN_LATENCY_LSB 26
+#define DDR_CONFIG2_GATE_OPEN_LATENCY_MASK 0x3c000000
+#define DDR_CONFIG2_GATE_OPEN_LATENCY_SET(x) \
+	(((x) << DDR_CONFIG2_GATE_OPEN_LATENCY_LSB) & DDR_CONFIG2_GATE_OPEN_LATENCY_MASK)
+#define DDR_CONFIG2_TWTR_LSB 21
+#define DDR_CONFIG2_TWTR_MASK 0x03e00000
+#define DDR_CONFIG2_TWTR_SET(x) \
+	(((x) << DDR_CONFIG2_TWTR_LSB) & DDR_CONFIG2_TWTR_MASK)
+#define DDR_CONFIG2_TRTP_LSB 17
+#define DDR_CONFIG2_TRTP_MASK 0x001e0000
+#define DDR_CONFIG2_TRTP_SET(x) \
+	(((x) << DDR_CONFIG2_TRTP_LSB) & DDR_CONFIG2_TRTP_MASK)
+#define DDR_CONFIG2_TRTW_LSB 12
+#define DDR_CONFIG2_TRTW_MASK 0x0001f000
+#define DDR_CONFIG2_TRTW_SET(x) \
+	(((x) << DDR_CONFIG2_TRTW_LSB) & DDR_CONFIG2_TRTW_MASK)
+#define DDR_CONFIG2_TWR_LSB 8
+#define DDR_CONFIG2_TWR_MASK 0x00000f00
+#define DDR_CONFIG2_TWR_SET(x) \
+	(((x) << DDR_CONFIG2_TWR_LSB) & DDR_CONFIG2_TWR_MASK)
+#define DDR_CONFIG2_CKE_LSB 7
+#define DDR_CONFIG2_CKE_MASK 0x00000080
+#define DDR_CONFIG2_CKE_SET(x) \
+	(((x) << DDR_CONFIG2_CKE_LSB) & DDR_CONFIG2_CKE_MASK)
+#define DDR_CONFIG2_CNTL_OE_EN_LSB 5
+#define DDR_CONFIG2_CNTL_OE_EN_MASK 0x00000020
+#define DDR_CONFIG2_CNTL_OE_EN_SET(x) \
+	(((x) << DDR_CONFIG2_CNTL_OE_EN_LSB) & DDR_CONFIG2_CNTL_OE_EN_MASK)
+#define DDR_CONFIG2_BURST_LENGTH_LSB 0
+#define DDR_CONFIG2_BURST_LENGTH_MASK 0x0000000f
+#define DDR_CONFIG2_BURST_LENGTH_SET(x) \
+	(((x) << DDR_CONFIG2_BURST_LENGTH_LSB) & DDR_CONFIG2_BURST_LENGTH_MASK)
+#define RST_BOOTSTRAP_ADDRESS		0x180600b0
+#define PMU2_SWREGMSB_LSB 22
+#define PMU2_SWREGMSB_MASK 0xffc00000
+#define PMU2_SWREGMSB_SET(x) \
+	(((x) << PMU2_SWREGMSB_LSB) & PMU2_SWREGMSB_MASK)
+#define PMU2_PGM_LSB 21
+#define PMU2_PGM_MASK 0x00200000
+#define PMU2_PGM_SET(x) \
+	(((x) << PMU2_PGM_LSB) & PMU2_PGM_MASK)
+
+#define CPU_DDR_SYNC_MODE DDR_CTL_CONFIG_CPU_DDR_SYNC_SET(0)
+
+/*
+* DDR2                      DDR1
+* 0x40c3   25MHz            0x4186   25Mhz
+* 0x4138   40MHz            0x4270   40Mhz
+*/
+#define CFG_DDR2_REFRESH_VAL 0x40c3
+#define CFG_DDR2_CONFIG_VAL DDR_CONFIG_CAS_LATENCY_MSB_SET(0x1) | \
+	DDR_CONFIG_OPEN_PAGE_SET(0x1) | DDR_CONFIG_CAS_LATENCY_SET(0x4) | \
+	DDR_CONFIG_TMRD_SET(0x6) | DDR_CONFIG_TRFC_SET(0x16) | \
+	DDR_CONFIG_TRRD_SET(0x7) | DDR_CONFIG_TRP_SET(0xb) | \
+	DDR_CONFIG_TRCD_SET(0xb) | DDR_CONFIG_TRAS_SET(0)
+#define CFG_DDR2_CONFIG2_VAL DDR_CONFIG2_HALF_WIDTH_LOW_SET(0x1) | \
+	DDR_CONFIG2_SWAP_A26_A27_SET(0x0) | DDR_CONFIG2_GATE_OPEN_LATENCY_SET(0xa) | \
+	DDR_CONFIG2_TWTR_SET(0x16) | DDR_CONFIG2_TRTP_SET(0xa) | \
+	DDR_CONFIG2_TRTW_SET(0xe) | DDR_CONFIG2_TWR_SET(0x2) | \
+	DDR_CONFIG2_CKE_SET(0x1) | DDR_CONFIG2_CNTL_OE_EN_SET(0x1) | \
+	DDR_CONFIG2_BURST_LENGTH_SET(0x8)
+
+#define CFG_DDR2_CONFIG3_VAL 0x0000000e
+#define CFG_DDR2_EXT_MODE_VAL1 0x782
+#define CFG_DDR2_EXT_MODE_VAL2 0x402
+#define CFG_DDR2_MODE_VAL_INIT 0xb53
+#define CFG_DDR2_MODE_VAL 0xa53
+#define CFG_DDR2_TAP_VAL 0x10
+#define CFG_DDR2_EN_TWL_VAL 0x00001e91
+#define CFG_DDR2_RD_DATA_THIS_CYCLE_VAL_16 0xffff
+
+#define CFG_DDR_CTL_CONFIG DDR_CTL_CONFIG_SRAM_TSEL_SET(0x1) | \
+	DDR_CTL_CONFIG_GE0_SRAM_SYNC_SET(0x1) | \
+	DDR_CTL_CONFIG_GE1_SRAM_SYNC_SET(0x1) | \
+	DDR_CTL_CONFIG_USB_SRAM_SYNC_SET(0x1) | \
+	DDR_CTL_CONFIG_PCIE_SRAM_SYNC_SET(0x1) | \
+	DDR_CTL_CONFIG_WMAC_SRAM_SYNC_SET(0x1) | \
+	DDR_CTL_CONFIG_MISC_SRC1_SRAM_SYNC_SET(0x1) | \
+	DDR_CTL_CONFIG_MISC_SRC2_SRAM_SYNC_SET(0x1)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void qca956x_ddr_init(void)
+{
+	u32 ddr_config, ddr_config2, ddr_config3, mod_val, \
+		mod_val_init, cycle_val, tap_val, ctl_config;
+	void __iomem *ddr_regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			       MAP_NOCACHE);
+	void __iomem *srif_regs = map_physmem(QCA956X_SRIF_BASE, QCA956X_SRIF_SIZE,
+			       MAP_NOCACHE);
+
+	ddr_config = CFG_DDR2_CONFIG_VAL;
+	ddr_config2 = CFG_DDR2_CONFIG2_VAL;
+	ddr_config3 = CFG_DDR2_CONFIG3_VAL;
+	mod_val_init = CFG_DDR2_MODE_VAL_INIT;
+	mod_val = CFG_DDR2_MODE_VAL;
+	tap_val = CFG_DDR2_TAP_VAL;
+	cycle_val = CFG_DDR2_RD_DATA_THIS_CYCLE_VAL_16;
+	ctl_config = CFG_DDR_CTL_CONFIG | DDR_CTL_CONFIG_PAD_DDR2_SEL_SET(0x1) |
+			 DDR_CTL_CONFIG_HALF_WIDTH_SET(0x1) | CPU_DDR_SYNC_MODE;
+
+	writel(0x10, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(0x20, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(ctl_config, ddr_regs + QCA956X_DDR_REG_CTL_CONF);
+	udelay(10);
+
+	writel(cycle_val, ddr_regs + AR71XX_DDR_REG_RD_CYCLE);
+	udelay(100);
+
+	writel(0x74444444, ddr_regs + QCA956X_DDR_REG_BURST);
+	udelay(100);
+
+	writel(0x44444444, ddr_regs + QCA956X_DDR_REG_BURST2);
+	udelay(100);
+
+	writel(DDR_FSM_WAIT_CTRL_VAL, ddr_regs + QCA956X_DDR_REG_FSM_WAIT_CTRL);
+	udelay(100);
+
+	writel(0xfffff, ddr_regs + QCA956X_DDR_REG_TIMEOUT_MAX);
+	udelay(100);
+
+	writel(ddr_config, ddr_regs + AR71XX_DDR_REG_CONFIG);
+	udelay(100);
+
+	writel(ddr_config2, ddr_regs + AR71XX_DDR_REG_CONFIG2);
+	udelay(100);
+
+	writel(ddr_config3, ddr_regs + QCA956X_DDR_REG_DDR3_CONFIG);
+	udelay(100);
+
+	writel(CFG_DDR2_EN_TWL_VAL, ddr_regs + QCA956X_DDR_REG_DDR2_CONFIG);
+	udelay(100);
+
+	writel(ddr_config2 | 0x80, ddr_regs + AR71XX_DDR_REG_CONFIG2);	/* CKE Enable */
+	udelay(100);
+
+	writel(0x8, ddr_regs + AR71XX_DDR_REG_CONTROL);	/* Precharge */
+	udelay(10);
+
+	writel(0, ddr_regs + QCA956X_DDR_REG_DDR2_EMR2);
+	writel(0x10, ddr_regs + AR71XX_DDR_REG_CONTROL);	/* EMR2 */
+	udelay(10);
+
+	writel(0, ddr_regs + QCA956X_DDR_REG_DDR2_EMR3);
+	writel(0x20, ddr_regs + AR71XX_DDR_REG_CONTROL);	/* EMR3 */
+	udelay(10);
+
+	/* EMR DLL enable, Reduced Driver Impedance control, Differential DQS disabled */
+	writel(CFG_DDR2_EXT_MODE_VAL2, ddr_regs + AR71XX_DDR_REG_EMR);
+	udelay(100);
+
+	writel(0x2, ddr_regs + AR71XX_DDR_REG_CONTROL); /* EMR write */
+	udelay(10);
+
+	writel(mod_val_init, ddr_regs + AR71XX_DDR_REG_MODE);
+	udelay(1000);
+
+	writel(0x1, ddr_regs + AR71XX_DDR_REG_CONTROL);	/* MR Write */
+	udelay(10);
+
+	writel(0x8, ddr_regs + AR71XX_DDR_REG_CONTROL);	/* Precharge */
+	udelay(10);
+
+	writel(0x4, ddr_regs + AR71XX_DDR_REG_CONTROL);	/* Auto Refresh */
+	udelay(10);
+
+	writel(0x4, ddr_regs + AR71XX_DDR_REG_CONTROL);	/* Auto Refresh */
+	udelay(10);
+
+	/* Issue MRS to remove DLL out-of-reset */
+	writel(mod_val, ddr_regs + AR71XX_DDR_REG_MODE);
+	udelay(100);
+
+	writel(0x1, ddr_regs + AR71XX_DDR_REG_CONTROL); /* MR write */
+	udelay(100);
+
+	writel(CFG_DDR2_EXT_MODE_VAL1, ddr_regs + AR71XX_DDR_REG_EMR);
+	udelay(100);
+
+	writel(0x2, ddr_regs + AR71XX_DDR_REG_CONTROL); /* EMR write */
+	udelay(100);
+
+	writel(CFG_DDR2_EXT_MODE_VAL2, ddr_regs + AR71XX_DDR_REG_EMR);
+	udelay(100);
+
+	writel(0x2, ddr_regs + AR71XX_DDR_REG_CONTROL); /* EMR write */
+	udelay(100);
+
+	writel(CFG_DDR2_REFRESH_VAL, ddr_regs + AR71XX_DDR_REG_REFRESH);
+	udelay(100);
+
+	writel(tap_val, ddr_regs + AR71XX_DDR_REG_TAP_CTRL0);
+	writel(tap_val, ddr_regs + AR71XX_DDR_REG_TAP_CTRL1);
+	writel(tap_val, ddr_regs + QCA956X_DDR_REG_TAP_CTRL2);
+	writel(tap_val, ddr_regs + QCA956X_DDR_REG_TAP_CTRL3);
+
+	writel(0x633c8176, srif_regs + QCA956X_SRIF_PMU1_REG);
+	/* Set DDR2 Voltage to 1.8 volts */
+	writel(PMU2_SWREGMSB_SET(0x40) | PMU2_PGM_SET(0x1),
+	       srif_regs + QCA956X_SRIF_PMU2_REG);
+}
diff --git a/arch/mips/mach-ath79/qca956x/qca956x-ddr-tap.S b/arch/mips/mach-ath79/qca956x/qca956x-ddr-tap.S
new file mode 100644
index 0000000000..db54b575fb
--- /dev/null
+++ b/arch/mips/mach-ath79/qca956x/qca956x-ddr-tap.S
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Rosy Song <rosysong@rosinson.com>
+ *
+ * Based on QSDK
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <mach/ar71xx_regs.h>
+
+    .set noreorder
+
+LEAF(ddr_tap_tuning)
+	li	a0, 0xbd001f00
+	sw	zero, 0x0(a0)			/* Place where the tap values are saved and used for SWEEP */
+	sw	zero, 0x4(a0)			/* Place where the number of passing taps are saved. */
+	sw	zero, 0x14(a0)		/* Place where the last pass tap value is stored */
+	li	a1, 0xaa55aa55		/* Indicates that the First pass tap value is not found */
+	sw	a1, 0x10(a0)		/* Place where the First pass tap value is stored */
+	 nop
+
+	li	a0, CKSEG1ADDR(AR71XX_RESET_BASE)		/* RESET_BASE_ADDRESS */
+	lw	a1, 0x1c(a0)		/* Reading the RST_RESET_ADDRESS */
+	li	a2, 0x08000000		/* Setting the RST_RESET_RTC_RESET */
+	or	a1, a1, a2
+	sw	a1, 0x1c(a0)
+
+	li	a3, 0xffffffff
+	xor	a2, a2, a3
+	and	a1, a1, a2
+	sw	a1, 0x1c(a0)		/* Taking the RTC out of RESET */
+	 nop
+
+	li	a0, CKSEG1ADDR(QCA956X_RTC_BASE)		/* RTC_BASE_ADDRESS */
+	li	a1, 0x1
+	sw	a1, 0x0040(a0)		/* RTC_SYNC_RESET_ADDRESS */
+
+	li	a2, 0x2
+
+_poll_for_RTC_ON:
+	lw	a1, 0x0044(a0)		/* RTC_SYNC_STATUS_ADDRESS */
+	and	a1, a2, a1
+	bne	a1, a2, _poll_for_RTC_ON
+	  nop
+
+_CHANGE_TAPS:
+	li	t0, 0xbd001f00		/* Read the current value of the TAP for programming */
+	lw	t1, 0x0(t0)
+	li	t2, 0x00000000
+	or	t3, t1, t2
+
+	li	t0, 0xb8000000		/* DDR_BASE_ADDRESS */
+	sw	t3, 0x1c(t0)		/* TAP_CONTROL_0_ADDRESS */
+	sw	t3, 0x20(t0)		/* TAP_CONTROL_1_ADDRESS */
+	sw	t3, 0x24(t0)		/* TAP_CONTROL_2_ADDRESS */
+	sw	t3, 0x28(t0)		/* TAP_CONTROL_3_ADDRESS */
+
+	li	t1, 0x00000010		/* Running the test 8 times */
+	sw	t1, 0x0068(t0)		/* PERF_COMP_ADDR_1_ADDRESS */
+
+	li	t1, 0xfa5de83f		/* 4 Row Address Bits, 4 Column Address Bits, 2 BA bits */
+	sw	t1, 0x002c(t0)		/* PERF_MASK_ADDR_0_ADDRESS */
+
+	li	t1, 0x0000ffff
+	sw	t1, 0x0070(t0)		/* PERF_COMP_AHB_GE0_1_ADDRESS */
+
+	li	t1, 0x0000ffff
+	sw	t1, 0x0040(t0)		/* PERF_COMP_AHB_GE1_0_ADDRESS */
+
+	li	t1, 0x0000ffff
+	sw	t1, 0x0078(t0)		/* PERF_COMP_AHB_GE1_1_ADDRESS */
+
+	li	t1, 0x0000ffff
+	sw	t1, 0x0034(t0)		/* PERF_MASK_AHB_GE0_0_ADDRESS */
+
+	li	t1, 0x0000ffff
+	sw	t1, 0x006c(t0)		/* PERF_MASK_AHB_GE0_1_ADDRESS */
+
+	li	t1, 0x0000ffff
+	sw	t1, 0x003c(t0)		/* PERF_MASK_AHB_GE1_0_ADDRESS */
+
+	li	t1, 0x0000ffff
+	sw	t1, 0x0074(t0)		/* PERF_MASK_AHB_GE1_1_ADDRESS */
+
+	li	t1, 0x0000ffff
+	sw	t1, 0x0038(t0)		/* PERF_COMP_AHB_GE0_0_ADDRESS */
+
+	li	t1, 0x00000001
+	sw	t1, 0x011c(t0)		/* DDR_BIST_ADDRESS */
+
+	li	t2, 0x1
+
+_bist_done_poll:
+	lw	t1, 0x0120(t0)		/* DDR_BIST_STATUS_ADDRESS */
+	and	t1, t1, t2
+	bne	t1, t2, _bist_done_poll
+	 nop
+
+	lw	t1, 0x0120(t0)		/* DDR_BIST_STATUS_ADDRESS */
+	li	t4, 0x000001fe
+	and	t2, t1, t4
+	srl	t2, t2, 0x1		/* no. of Pass Runs */
+
+	li	t5, 0x00000000
+	sw	t5, 0x011c(t0)		/* DDR_BIST_ADDRESS	- Stop the DDR BIST test */
+
+	li	t5, 0x0001fe00
+	and	t5, t5, t1
+	bnez	t5, _iterate_tap		/* This is a redundant compare but nevertheless - Comparing the FAILS */
+	 nop
+
+	lw	t1, 0x0068(t0)		/* PERF_COMP_ADDR_1_ADDRESS */
+	li	t3, 0x000001fe
+	and	t3, t3, t1
+	srl	t3, t3, 0x1		/* No. of runs in the config register. */
+	bne	t3, t2, _iterate_tap
+	 nop
+
+pass_tap:
+	li	t0, 0xbd001f00
+	lw	t1, 0x4(t0)
+	addiu	t1, t1, 0x1
+	sw	t1, 0x4(t0)
+
+	li	t0, 0xbd001f10
+	lw	t1, 0x0(t0)
+	li	t2, 0xaa55aa55
+	beq	t1, t2, _first_pass
+	 nop
+
+	li	t0, 0xbd001f00
+	lw	t1, 0x0(t0)
+	li	t0, 0xbd001f10
+	sw	t1, 0x4(t0)
+	 nop
+	b	_iterate_tap
+	 nop
+
+_first_pass:
+	li	t0, 0xbd001f00
+	lw	t1, 0x0(t0)
+	li	t0, 0xbd001f10
+	sw	t1, 0x0(t0)
+	sw	t1, 0x4(t0)
+	 nop
+
+_iterate_tap:
+	li	t0, 0xbd001f00
+	lw	t1, 0x0(t0)
+	li	t2, 0x3f
+	beq	t1, t2, _STOP_TEST
+	 nop
+
+	addiu	t1, t1, 0x1
+	sw	t1, 0x0(t0)
+	 nop
+	b	_CHANGE_TAPS
+	 nop
+
+_STOP_TEST:
+	li	t0, 0xbd001f00
+	lw	t1, 0x4(t0)
+	bnez	t1, _load_center_tap
+	 nop
+
+	li	t3, 0x8			/* Default Tap to be used */
+	b	_load_tap_into_reg
+	 nop
+
+_load_center_tap:
+	li	t0, 0xbd001f10
+	lw	t1, 0x0(t0)
+	lw	t2, 0x4(t0)
+	add	t3, t1, t2
+	srl	t3, t3, 0x1
+	li	t4, 0x3f
+	and	t3, t3, t4
+
+_load_tap_into_reg:
+	li	t0, 0xb8000000
+	sw	t3, 0x1c(t0)		/* TAP_CONTROL_0_ADDRESS */
+	sw	t3, 0x20(t0)		/* TAP_CONTROL_1_ADDRESS */
+	sw	t3, 0x24(t0)		/* TAP_CONTROL_2_ADDRESS */
+	sw	t3, 0x28(t0)		/* TAP_CONTROL_3_ADDRESS */
+
+	 nop
+	jr ra
+	 nop
+    END(ddr_tap_tuning)
diff --git a/arch/mips/mach-ath79/reset.c b/arch/mips/mach-ath79/reset.c
index 6a94d886f9..0ab3ab6383 100644
--- a/arch/mips/mach-ath79/reset.c
+++ b/arch/mips/mach-ath79/reset.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Copyright (C) 2018-2019 Rosy Song <rosysong@rosinson.com>
  */
 
 #include <common.h>
@@ -11,6 +12,44 @@
 #include <mach/ath79.h>
 #include <mach/ar71xx_regs.h>
 
+/* QCA956X ETH_SGMII_SERDES Registers */
+#define SGMII_SERDES_RES_CALIBRATION_LSB 23
+#define SGMII_SERDES_RES_CALIBRATION_MASK 0x07800000
+#define SGMII_SERDES_RES_CALIBRATION_SET(x) \
+	(((x) << SGMII_SERDES_RES_CALIBRATION_LSB) & SGMII_SERDES_RES_CALIBRATION_MASK)
+#define SGMII_SERDES_CDR_BW_LSB 1
+#define SGMII_SERDES_CDR_BW_MASK 0x00000006
+#define SGMII_SERDES_CDR_BW_SET(x) \
+	(((x) << SGMII_SERDES_CDR_BW_LSB) & SGMII_SERDES_CDR_BW_MASK)
+#define SGMII_SERDES_TX_DR_CTRL_LSB 4
+#define SGMII_SERDES_TX_DR_CTRL_MASK 0x00000070
+#define SGMII_SERDES_TX_DR_CTRL_SET(x) \
+	(((x) << SGMII_SERDES_TX_DR_CTRL_LSB) & SGMII_SERDES_TX_DR_CTRL_MASK)
+#define SGMII_SERDES_PLL_BW_LSB 8
+#define SGMII_SERDES_PLL_BW_MASK 0x00000100
+#define SGMII_SERDES_PLL_BW_SET(x) \
+	(((x) << SGMII_SERDES_PLL_BW_LSB) & SGMII_SERDES_PLL_BW_MASK)
+#define SGMII_SERDES_EN_SIGNAL_DETECT_LSB 16
+#define SGMII_SERDES_EN_SIGNAL_DETECT_MASK 0x00010000
+#define SGMII_SERDES_EN_SIGNAL_DETECT_SET(x) \
+	(((x) << SGMII_SERDES_EN_SIGNAL_DETECT_LSB) & SGMII_SERDES_EN_SIGNAL_DETECT_MASK)
+#define SGMII_SERDES_FIBER_SDO_LSB 17
+#define SGMII_SERDES_FIBER_SDO_MASK 0x00020000
+#define SGMII_SERDES_FIBER_SDO_SET(x) \
+	(((x) << SGMII_SERDES_FIBER_SDO_LSB) & SGMII_SERDES_FIBER_SDO_MASK)
+#define SGMII_SERDES_VCO_REG_LSB 27
+#define SGMII_SERDES_VCO_REG_MASK 0x78000000
+#define SGMII_SERDES_VCO_REG_SET(x) \
+	(((x) << SGMII_SERDES_VCO_REG_LSB) & SGMII_SERDES_VCO_REG_MASK)
+#define SGMII_SERDES_VCO_FAST_LSB 9
+#define SGMII_SERDES_VCO_FAST_MASK 0x00000200
+#define SGMII_SERDES_VCO_FAST_GET(x) \
+	(((x) & SGMII_SERDES_VCO_FAST_MASK) >> SGMII_SERDES_VCO_FAST_LSB)
+#define SGMII_SERDES_VCO_SLOW_LSB 10
+#define SGMII_SERDES_VCO_SLOW_MASK 0x00000400
+#define SGMII_SERDES_VCO_SLOW_GET(x) \
+	(((x) & SGMII_SERDES_VCO_SLOW_MASK) >> SGMII_SERDES_VCO_SLOW_LSB)
+
 void _machine_restart(void)
 {
 	void __iomem *base;
@@ -152,6 +191,236 @@ static int eth_init_qca953x(void)
 	return 0;
 }
 
+static int qca956x_sgmii_cal(void)
+{
+	int i;
+	u32 reg, rev_sgmii_val;
+	u32 vco_fast, vco_slow;
+	u32 start_val = 0, end_val = 0;
+	void __iomem *gregs = map_physmem(AR71XX_MII_BASE, AR71XX_MII_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+					  MAP_NOCACHE);
+	const u32 mask = QCA956X_RESET_SGMII_ASSERT | QCA956X_RESET_SGMII;
+
+	writel(BIT(2) | BIT(0), pregs + QCA956X_PLL_ETH_SGMII_SERDES_REG);
+
+	reg = readl(gregs + QCA956X_GMAC_REG_SGMII_SERDES);
+	vco_fast = SGMII_SERDES_VCO_FAST_GET(reg);
+	vco_slow = SGMII_SERDES_VCO_SLOW_GET(reg);
+
+	/* Set resistor calibration from 0000 to 1111 */
+	for (i = 0; i < 0x10; i++) {
+		reg = (readl(gregs + QCA956X_GMAC_REG_SGMII_SERDES) &
+		      ~SGMII_SERDES_RES_CALIBRATION_MASK) |
+		      SGMII_SERDES_RES_CALIBRATION_SET(i);
+		writel(reg, gregs + QCA956X_GMAC_REG_SGMII_SERDES);
+
+		udelay(50);
+
+		reg = readl(gregs + QCA956X_GMAC_REG_SGMII_SERDES);
+		if (vco_fast != SGMII_SERDES_VCO_FAST_GET(reg) ||
+		    vco_slow != SGMII_SERDES_VCO_SLOW_GET(reg)) {
+			if (start_val == 0) {
+				start_val = i;
+				end_val = i;
+			} else {
+				end_val = i;
+			}
+		}
+		vco_fast = SGMII_SERDES_VCO_FAST_GET(reg);
+		vco_slow = SGMII_SERDES_VCO_SLOW_GET(reg);
+	}
+
+	if (start_val == 0)
+		rev_sgmii_val = 0x7;
+	else
+		rev_sgmii_val = (start_val + end_val) >> 1;
+
+	writel((readl(gregs + QCA956X_GMAC_REG_SGMII_SERDES) &
+	       ~SGMII_SERDES_RES_CALIBRATION_MASK) |
+	       SGMII_SERDES_RES_CALIBRATION_SET(rev_sgmii_val),
+	       gregs + QCA956X_GMAC_REG_SGMII_SERDES);
+
+	writel(BIT(2) | BIT(0), pregs + QCA956X_PLL_ETH_SGMII_SERDES_REG);
+
+	reg = readl(gregs + QCA956X_GMAC_REG_SGMII_SERDES);
+	writel(SGMII_SERDES_CDR_BW_SET(3) | SGMII_SERDES_TX_DR_CTRL_SET(1) |
+	       SGMII_SERDES_PLL_BW_SET(1) | SGMII_SERDES_EN_SIGNAL_DETECT_SET(1) |
+	       SGMII_SERDES_FIBER_SDO_SET(1) | SGMII_SERDES_VCO_REG_SET(3) | reg,
+	       gregs + QCA956X_GMAC_REG_SGMII_SERDES);
+
+	setbits_be32(rregs + QCA956X_RESET_REG_RESET_MODULE, mask);
+	mdelay(1);
+	clrbits_be32(rregs + QCA956X_RESET_REG_RESET_MODULE, mask);
+	mdelay(1);
+
+	while (!(readl(gregs + QCA956X_GMAC_REG_SGMII_SERDES) & BIT(15)))
+		/* NOP */;
+
+	return 0;
+}
+
+static int qca956x_sgmii_setup(void)
+{
+	int i;
+	u32 s = 0, reg = 0;
+	u32 _regs[] = {
+		BIT(4),	/* HW_RX_125M_N */
+		BIT(2),	/* RX_125M_N */
+		BIT(3),	/* TX_125M_N */
+		BIT(0),	/* RX_CLK_N */
+		BIT(1),	/* TX_CLK_N */
+	};
+	void __iomem *gregs = map_physmem(AR71XX_MII_BASE, AR71XX_MII_SIZE,
+					  MAP_NOCACHE);
+
+	/* Force sgmii mode */
+	writel(BIT(6) | BIT(15) | BIT(8), gregs + QCA956X_GMAC_REG_MR_AN_CTRL);
+	udelay(10);
+	writel(0x2 | BIT(5) | (0x2 << 6), gregs + QCA956X_GMAC_REG_SGMII_CONFIG);
+
+	/* SGMII reset sequence sugguest by qca systems team. */
+	writel(0, gregs + QCA956X_GMAC_REG_SGMII_RESET);
+	for (i = 0; i < ARRAY_SIZE(_regs); i++) {
+		reg |= _regs[i];
+		writel(reg, gregs + QCA956X_GMAC_REG_SGMII_RESET);
+	}
+
+	writel(readl(gregs + QCA956X_GMAC_REG_MR_AN_CTRL) & ~BIT(15),
+	       gregs + QCA956X_GMAC_REG_MR_AN_CTRL);
+
+	/*
+	 * WARNING: Across resets SGMII link status goes to weird state.
+	 * if 0xb8070058 (SGMII_DEBUG Register) reads other than 0xf or 0x10
+	 * for sure we are in bad state.
+	 * Issue a PHY RESET in MR_AN_CONTROL_ADDRESS to keep going.
+	 */
+	i = 0;
+	s = (readl(gregs + QCA956X_GMAC_REG_SGMII_DEBUG) & 0xff);
+	while (!(s == 0xf || s == 0x10)) {
+		writel(readl(gregs + QCA956X_GMAC_REG_MR_AN_CTRL) | BIT(15),
+		       gregs + QCA956X_GMAC_REG_MR_AN_CTRL);
+		udelay(100);
+		writel(readl(gregs + QCA956X_GMAC_REG_MR_AN_CTRL) & ~BIT(15),
+		       gregs + QCA956X_GMAC_REG_MR_AN_CTRL);
+		if (i++ == 10)
+			break;
+		s = (readl(gregs + QCA956X_GMAC_REG_SGMII_DEBUG) & 0xff);
+	}
+
+	return 0;
+}
+
+static int qca956x_s17_reset(void)
+{
+	void __iomem *regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+					  MAP_NOCACHE);
+	const u32 mask = QCA956X_RESET_SGMII_ASSERT | QCA956X_RESET_SGMII |
+			 QCA956X_RESET_EXTERNAL | QCA956X_RESET_SGMII_ANALOG |
+			 QCA956X_RESET_SWITCH;
+	/* Bits(Reserved in datasheet) should be set to 1 */
+	const u32 mask_r = QCA956X_RESET_SGMII_ASSERT | QCA956X_RESET_SGMII |
+			 QCA956X_RESET_EXTERNAL;
+
+	setbits_be32(rregs + QCA956X_RESET_REG_RESET_MODULE, mask);
+	mdelay(1);
+	clrbits_be32(rregs + QCA956X_RESET_REG_RESET_MODULE, mask_r);
+	mdelay(1);
+
+	/* Reset s17 switch(GPIO11) SYS_RST_L */
+	writel(readl(regs + AR71XX_GPIO_REG_OE) & ~BIT(11),
+	       regs + AR71XX_GPIO_REG_OE);
+	udelay(100);
+
+	writel(readl(regs + AR71XX_GPIO_REG_OUT) & ~BIT(11),
+	       regs + AR71XX_GPIO_REG_OUT);
+	udelay(100);
+	writel(readl(regs + AR71XX_GPIO_REG_OUT) | BIT(11),
+	       regs + AR71XX_GPIO_REG_OUT);
+
+	return 0;
+}
+
+static int qca956x_init_mdio(void)
+{
+	u32 reg;
+	void __iomem *regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+						MAP_NOCACHE);
+	void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+					  MAP_NOCACHE);
+	const u32 mask = QCA956X_RESET_GE0_MDIO | QCA956X_RESET_GE0_MAC |
+			 QCA956X_RESET_GE1_MDIO | QCA956X_RESET_GE1_MAC;
+
+	setbits_be32(rregs + QCA956X_RESET_REG_RESET_MODULE, mask);
+	mdelay(1);
+	clrbits_be32(rregs + QCA956X_RESET_REG_RESET_MODULE, mask);
+	mdelay(1);
+
+	/* GPIO4 as MDI */
+	reg = readl(regs + QCA956X_GPIO_REG_IN_ENABLE3);
+	reg &= ~(0xff << 16);
+	reg |= (0x4 << 16);
+	writel(reg, regs + QCA956X_GPIO_REG_IN_ENABLE3);
+
+	/* GPIO4 as MDO */
+	reg = readl(regs + QCA956X_GPIO_REG_OUT_FUNC1);
+	reg &= ~0xff;
+	reg |= 0x20;
+	writel(reg, regs + QCA956X_GPIO_REG_OUT_FUNC1);
+
+	/* Init MDC(GPIO3) / MDIO(GPIO4) */
+	reg = readl(regs + AR71XX_GPIO_REG_OE);
+	reg &= ~BIT(4);
+	writel(reg, regs + AR71XX_GPIO_REG_OE);
+	udelay(100);
+
+	reg = readl(regs + AR71XX_GPIO_REG_OE);
+	reg &= ~BIT(3);
+	writel(reg, regs + AR71XX_GPIO_REG_OE);
+	udelay(100);
+
+	/* GPIO3 as MDI */
+	reg = readl(regs + QCA956X_GPIO_REG_OUT_FUNC0);
+	reg &= ~(0xff << 24);
+	reg |= (0x21 << 24);
+	writel(reg, regs + QCA956X_GPIO_REG_OUT_FUNC0);
+
+	return 0;
+}
+
+static int eth_init_qca956x(void)
+{
+	void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *gregs = map_physmem(AR71XX_MII_BASE, AR71XX_MII_SIZE,
+					  MAP_NOCACHE);
+
+	qca956x_sgmii_cal();
+	qca956x_s17_reset();
+	qca956x_init_mdio();
+
+	if (ath79_get_bootstrap() & QCA956X_BOOTSTRAP_REF_CLK_40)
+		writel(0x45500, pregs + QCA956X_PLL_SWITCH_CLK_CTRL_REG);
+	else
+		writel(0xc5200, pregs + QCA956X_PLL_SWITCH_CLK_CTRL_REG);
+
+	qca956x_sgmii_setup();
+
+	writel((3 << 16) | (3 << 14) | (1 << 0) | (1 << 6),
+	       gregs + QCA956X_GMAC_REG_ETH_CFG);
+
+	writel((1 << 31) | (2 << 28) | (2 << 26) | (1 << 25),
+	       pregs + QCA956X_PLL_ETH_XMII_CTRL_REG);
+	mdelay(1);
+
+	return 0;
+}
+
 int ath79_eth_reset(void)
 {
 	/*
@@ -164,6 +433,8 @@ int ath79_eth_reset(void)
 		return eth_init_ar934x();
 	if (soc_is_qca953x())
 		return eth_init_qca953x();
+	if (soc_is_qca956x())
+		return eth_init_qca956x();
 
 	return -EINVAL;
 }
diff --git a/board/qca/ap152/Kconfig b/board/qca/ap152/Kconfig
new file mode 100644
index 0000000000..f6ad498e85
--- /dev/null
+++ b/board/qca/ap152/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_AP152
+
+config SYS_VENDOR
+	default "qca"
+
+config SYS_BOARD
+	default "ap152"
+
+config SYS_CONFIG_NAME
+	default "ap152"
+
+config SYS_TEXT_BASE
+	default 0x9f000000
+
+endif
diff --git a/board/qca/ap152/MAINTAINERS b/board/qca/ap152/MAINTAINERS
new file mode 100644
index 0000000000..785ec2766d
--- /dev/null
+++ b/board/qca/ap152/MAINTAINERS
@@ -0,0 +1,6 @@
+AP152 BOARD
+M:	Rosy Song <rosysong@rosinson.com>
+S:	Maintained
+F:	board/qca/ap152/
+F:	include/configs/ap152.h
+F:	configs/ap152_defconfig
diff --git a/board/qca/ap152/Makefile b/board/qca/ap152/Makefile
new file mode 100644
index 0000000000..4270afa129
--- /dev/null
+++ b/board/qca/ap152/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y	= ap152.o
diff --git a/board/qca/ap152/ap152.c b/board/qca/ap152/ap152.c
new file mode 100644
index 0000000000..30cd56563b
--- /dev/null
+++ b/board/qca/ap152/ap152.c
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Rosy Song <rosysong@rosinson.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/ddr.h>
+#include <mach/ath79.h>
+#include <debug_uart.h>
+
+#define RST_RESET_RTC_RESET_LSB 27
+#define RST_RESET_RTC_RESET_MASK 0x08000000
+#define RST_RESET_RTC_RESET_SET(x) \
+	(((x) << RST_RESET_RTC_RESET_LSB) & RST_RESET_RTC_RESET_MASK)
+
+#ifdef CONFIG_DEBUG_UART_BOARD_INIT
+void board_debug_uart_init(void)
+{
+	void __iomem *regs;
+	u32 val;
+
+	regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+			   MAP_NOCACHE);
+
+	/* UART : RX18, TX22 done
+	 * GPIO18 as input, GPIO22 as output
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_OE);
+	val |= QCA956X_GPIO(18);
+	val &= ~QCA956X_GPIO(22);
+	writel(val, regs + AR71XX_GPIO_REG_OE);
+
+	/*
+	 * Enable GPIO22 as UART0_SOUT
+	 */
+	val = readl(regs + QCA956X_GPIO_REG_OUT_FUNC5);
+	val &= ~QCA956X_GPIO_MUX_MASK(16);
+	val |= QCA956X_GPIO_OUT_MUX_UART0_SOUT << 16;
+	writel(val, regs + QCA956X_GPIO_REG_OUT_FUNC5);
+
+	/*
+	 * Enable GPIO18 as UART0_SIN
+	 */
+	val = readl(regs + QCA956X_GPIO_REG_IN_ENABLE0);
+	val &= ~QCA956X_GPIO_MUX_MASK(8);
+	val |= QCA956X_GPIO_IN_MUX_UART0_SIN << 8;
+	writel(val, regs + QCA956X_GPIO_REG_IN_ENABLE0);
+
+	/*
+	 * Enable GPIO22 output
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_OUT);
+	val |= QCA956X_GPIO(22);
+	writel(val, regs + AR71XX_GPIO_REG_OUT);
+}
+#endif
+
+int board_early_init_f(void)
+{
+	u32 reg;
+	void __iomem *rst_regs = map_physmem(AR71XX_RESET_BASE,
+							 AR71XX_RESET_SIZE, MAP_NOCACHE);
+
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	/* CPU:775, DDR:650, AHB:258 */
+	qca956x_pll_init();
+	qca956x_ddr_init();
+#endif
+
+	/* Take WMAC out of reset */
+	reg = readl(rst_regs + QCA956X_RESET_REG_RESET_MODULE);
+	reg &= (~RST_RESET_RTC_RESET_SET(1));
+	writel(reg, rst_regs + QCA956X_RESET_REG_RESET_MODULE);
+
+	ath79_eth_reset();
+	return 0;
+}
diff --git a/configs/ap152_defconfig b/configs/ap152_defconfig
new file mode 100644
index 0000000000..21cb6eb742
--- /dev/null
+++ b/configs/ap152_defconfig
@@ -0,0 +1,49 @@
+CONFIG_MIPS=y
+CONFIG_SYS_TEXT_BASE=0x9F000000
+CONFIG_SYS_MALLOC_F_LEN=0x800
+CONFIG_SYS_CACHE_SIZE_AUTO=y
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_DEBUG_UART_BASE=0xb8020000
+CONFIG_DEBUG_UART_CLOCK=25000000
+CONFIG_ARCH_ATH79=y
+CONFIG_TARGET_AP152=y
+CONFIG_DEBUG_UART=y
+CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=squashfs"
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_SYS_PROMPT="ap152 # "
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_CRC32 is not set
+CONFIG_CMD_MEMTEST=y
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_MTDIDS_DEFAULT="nor0=spi-flash.0"
+CONFIG_MTDPARTS_DEFAULT="mtdparts=spi-flash.0:256k(u-boot),64k(u-boot-env),6336k(rootfs),1472k(uImage),64k(ART)"
+# CONFIG_ISO_PARTITION is not set
+CONFIG_DEFAULT_DEVICE_TREE="ap152"
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+# CONFIG_NET is not set
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_DATAFLASH=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_ATH79_SPI=y
+CONFIG_LZMA=y
diff --git a/include/configs/ap152.h b/include/configs/ap152.h
new file mode 100644
index 0000000000..c948a44054
--- /dev/null
+++ b/include/configs/ap152.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Rosy Song <rosysong@rosinson.com>
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_SYS_HZ                   1000
+#define CONFIG_SYS_MHZ                  375
+#define CONFIG_SYS_MIPS_TIMER_FREQ      (CONFIG_SYS_MHZ * 1000000)
+
+#define CONFIG_SYS_MONITOR_BASE         CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_SYS_MALLOC_LEN           0x40000
+#define CONFIG_SYS_BOOTPARAMS_LEN       0x20000
+
+#define CONFIG_SYS_SDRAM_BASE           0x80000000
+#define CONFIG_SYS_LOAD_ADDR            0x81000000
+
+#define CONFIG_SYS_INIT_RAM_ADDR        0xbd000000
+#define CONFIG_SYS_INIT_RAM_SIZE        0x2000
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE - 1)
+
+/*
+ * Serial Port
+ */
+#define CONFIG_SYS_NS16550_CLK          25000000
+#define CONFIG_SYS_BAUDRATE_TABLE \
+	{9600, 19200, 38400, 57600, 115200}
+
+#define CONFIG_BOOTCOMMAND              "sf probe;" \
+					"mtdparts default;" \
+					"bootm 0x9f060000"
+
+#define CONFIG_ENV_SPI_MAX_HZ           25000000
+#define CONFIG_ENV_OFFSET               0x40000
+#define CONFIG_ENV_SECT_SIZE            0x10000
+#define CONFIG_ENV_SIZE                 0x10000
+
+/* Miscellaneous configurable options */
+
+/*
+ * Diagnostics
+ */
+#define CONFIG_SYS_MEMTEST_START        0x80100000
+#define CONFIG_SYS_MEMTEST_END          0x83f00000
+
+#endif  /* __CONFIG_H */
-- 
2.17.1

             reply	other threads:[~2019-03-08  1:24 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-08  1:24 rosysong at rosinson.com [this message]
2019-03-15 11:19 ` [U-Boot] [U-Boot, V4, PATCH 1/1] mips: add initial support for qca956x referenced board Daniel Schwierzeck
2019-03-15 11:44 ` Daniel Schwierzeck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190308012426.13605-1-rosysong@rosinson.com \
    --to=rosysong@rosinson.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.