[PATCH 08/16] mips: mtmips: rewrite lowlevel codes of mt7628

Weijie Gao weijie.gao at mediatek.com
Wed Jan 8 04:01:31 CET 2020


This patch rewrites the mtmips architecture with the following changes:

1. Move MT7628 soc parts into a subfolder.
2. Lock parts of D-Cache as temporary stack.
3. Reimplement DDR initialization in C language.
4. Reimplement DDR calibration in a clear logic.
5. Add full support for auto size detection for DDR1 and DDR2.
6. Use accurate CPU clock depending for timer and delay functions.
   Xtal:25MHz -> CPU:575MHz / Xtal:40MHz -> CPU:580MHz.
7. Remove unusable nodes from mt7628a.dtsi

Note:

print_cpuinfo() has incompatible parts with MT7620 so it's moved into
mt7628 subfolder.

Signed-off-by: Weijie Gao <weijie.gao at mediatek.com>
---
 arch/mips/dts/mt7628a.dtsi                    |  76 +---
 arch/mips/include/asm/global_data.h           |   3 +
 arch/mips/mach-mtmips/Kconfig                 |  71 +---
 arch/mips/mach-mtmips/Makefile                |   7 +-
 arch/mips/mach-mtmips/cpu.c                   |  58 +---
 arch/mips/mach-mtmips/ddr_cal.c               | 211 +++++++++++
 arch/mips/mach-mtmips/ddr_calibrate.c         | 309 -----------------
 arch/mips/mach-mtmips/ddr_init.c              | 194 +++++++++++
 arch/mips/mach-mtmips/include/mach/ddr.h      |  52 +++
 arch/mips/mach-mtmips/include/mach/mc.h       | 180 ++++++++++
 arch/mips/mach-mtmips/lowlevel_init.S         | 328 ------------------
 arch/mips/mach-mtmips/mt7628/Makefile         |   5 +
 arch/mips/mach-mtmips/mt7628/ddr.c            | 173 +++++++++
 arch/mips/mach-mtmips/mt7628/init.c           | 109 ++++++
 arch/mips/mach-mtmips/mt7628/lowlevel_init.S  | 155 +++++++++
 arch/mips/mach-mtmips/mt7628/mt7628.h         |  90 +++++
 arch/mips/mach-mtmips/mt76xx.h                |  32 --
 ...gardena-smart-gateway-mt7688-ram_defconfig |   2 +-
 .../gardena-smart-gateway-mt7688_defconfig    |   4 +-
 configs/linkit-smart-7688-ram_defconfig       |   2 +-
 configs/linkit-smart-7688_defconfig           |   4 +-
 21 files changed, 1195 insertions(+), 870 deletions(-)
 create mode 100644 arch/mips/mach-mtmips/ddr_cal.c
 delete mode 100644 arch/mips/mach-mtmips/ddr_calibrate.c
 create mode 100644 arch/mips/mach-mtmips/ddr_init.c
 create mode 100644 arch/mips/mach-mtmips/include/mach/ddr.h
 create mode 100644 arch/mips/mach-mtmips/include/mach/mc.h
 delete mode 100644 arch/mips/mach-mtmips/lowlevel_init.S
 create mode 100644 arch/mips/mach-mtmips/mt7628/Makefile
 create mode 100644 arch/mips/mach-mtmips/mt7628/ddr.c
 create mode 100644 arch/mips/mach-mtmips/mt7628/init.c
 create mode 100644 arch/mips/mach-mtmips/mt7628/lowlevel_init.S
 create mode 100644 arch/mips/mach-mtmips/mt7628/mt7628.h
 delete mode 100644 arch/mips/mach-mtmips/mt76xx.h

diff --git a/arch/mips/dts/mt7628a.dtsi b/arch/mips/dts/mt7628a.dtsi
index 76a80c8952..3d7b839e6d 100644
--- a/arch/mips/dts/mt7628a.dtsi
+++ b/arch/mips/dts/mt7628a.dtsi
@@ -7,24 +7,6 @@
 	#size-cells = <1>;
 	compatible = "ralink,mt7628a-soc";
 
-	cpus {
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		cpu at 0 {
-			compatible = "mti,mips24KEc";
-			device_type = "cpu";
-			reg = <0>;
-		};
-	};
-
-	cpuintc: interrupt-controller {
-		#address-cells = <0>;
-		#interrupt-cells = <1>;
-		interrupt-controller;
-		compatible = "mti,cpu-interrupt-controller";
-	};
-
 	clk48m: clk48m at 0 {
 		compatible = "fixed-clock";
 
@@ -41,16 +23,11 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-		sysc: system-controller at 0 {
-			compatible = "ralink,mt7620a-sysc", "syscon";
-			reg = <0x0 0x100>;
-		};
+		resetctl-reboot {
+			compatible = "resetctl-reboot";
 
-		syscon-reboot {
-			compatible = "syscon-reboot";
-			regmap = <&sysc>;
-			offset = <0x34>;
-			mask = <0x1>;
+			resets = <&rstctrl MT7628_SYS_RST>;
+			reset-names = "sysreset";
 		};
 
 		clkctrl: clkctrl at 0x2c {
@@ -223,32 +200,6 @@
 
 			resets = <&rstctrl MT7628_TIMER_RST>;
 			reset-names = "wdt";
-
-			interrupt-parent = <&intc>;
-			interrupts = <24>;
-		};
-
-		intc: interrupt-controller at 200 {
-			compatible = "ralink,rt2880-intc";
-			reg = <0x200 0x100>;
-
-			interrupt-controller;
-			#interrupt-cells = <1>;
-
-			resets = <&rstctrl MT7628_INT_RST>;
-			reset-names = "intc";
-
-			interrupt-parent = <&cpuintc>;
-			interrupts = <2>;
-
-			ralink,intc-registers = <0x9c 0xa0
-						 0x6c 0xa4
-						 0x80 0x78>;
-		};
-
-		memory-controller at 300 {
-			compatible = "ralink,mt7620a-memc";
-			reg = <0x300 0x100>;
 		};
 
 		gpio at 600 {
@@ -261,9 +212,6 @@
 			resets = <&rstctrl MT7628_PIO_RST>;
 			reset-names = "pio";
 
-			interrupt-parent = <&intc>;
-			interrupts = <6>;
-
 			gpio0: bank at 0 {
 				reg = <0>;
 				compatible = "mtk,mt7621-gpio-bank";
@@ -311,9 +259,6 @@
 			resets = <&rstctrl MT7628_UART0_RST>;
 			reset-names = "uart0";
 
-			interrupt-parent = <&intc>;
-			interrupts = <20>;
-
 			reg-shift = <2>;
 		};
 
@@ -329,9 +274,6 @@
 			resets = <&rstctrl MT7628_UART1_RST>;
 			reset-names = "uart1";
 
-			interrupt-parent = <&intc>;
-			interrupts = <21>;
-
 			reg-shift = <2>;
 		};
 
@@ -347,9 +289,6 @@
 			resets = <&rstctrl MT7628_UART2_RST>;
 			reset-names = "uart2";
 
-			interrupt-parent = <&intc>;
-			interrupts = <22>;
-
 			reg-shift = <2>;
 		};
 	};
@@ -361,8 +300,6 @@
 
 		resets = <&rstctrl MT7628_EPHY_RST>;
 		reset-names = "ephy";
-
-		syscon = <&sysc>;
 	};
 
 	usb_phy: usb-phy at 10120000 {
@@ -371,8 +308,6 @@
 
 		#phy-cells = <0>;
 
-		ralink,sysctl = <&sysc>;
-
 		resets = <&rstctrl MT7628_UPHY_RST>;
 		reset-names = "phy";
 
@@ -386,9 +321,6 @@
 
 		phys = <&usb_phy>;
 		phy-names = "usb";
-
-		interrupt-parent = <&intc>;
-		interrupts = <18>;
 	};
 
 	mmc: mmc at 10130000 {
diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
index 7b4ad083ba..4c30fab871 100644
--- a/arch/mips/include/asm/global_data.h
+++ b/arch/mips/include/asm/global_data.h
@@ -27,6 +27,9 @@ struct arch_global_data {
 #ifdef CONFIG_MIPS_L2_CACHE
 	unsigned short l2_line_size;
 #endif
+#ifdef CONFIG_ARCH_MTMIPS
+	unsigned long timer_freq;
+#endif
 };
 
 #include <asm-generic/global_data.h>
diff --git a/arch/mips/mach-mtmips/Kconfig b/arch/mips/mach-mtmips/Kconfig
index 8e10719b27..e0076b613f 100644
--- a/arch/mips/mach-mtmips/Kconfig
+++ b/arch/mips/mach-mtmips/Kconfig
@@ -19,14 +19,22 @@ config SYS_ICACHE_SIZE
 config SYS_ICACHE_LINE_SIZE
 	default 32
 
+config SYS_TEXT_BASE
+	default 0x9c000000
+
 choice
 	prompt "MediaTek MIPS SoC select"
 
 config SOC_MT7628
 	bool "MT7628"
 	select MIPS_L1_CACHE_SHIFT_5
+	select MIPS_INIT_STACK_IN_SRAM
+	select MIPS_SRAM_INIT
+	select SYS_MIPS_CACHE_INIT_RAM_LOAD
+	select MIPS_OVERRIDE_GET_TBCLK
 	select PINCTRL_MT7628
 	select MTK_SERIAL
+	select SYSRESET_RESETCTL
 	help
 	  This supports MediaTek MT7628/MT7688.
 
@@ -78,69 +86,6 @@ config BOOT_ROM
 
 endchoice
 
-choice
-	prompt "DDR2 size"
-
-config ONBOARD_DDR2_SIZE_256MBIT
-	bool "256MBit (32MByte) total size"
-	depends on BOOT_ROM
-	help
-	  Use 256MBit (32MByte) of DDR total size
-
-config ONBOARD_DDR2_SIZE_512MBIT
-	bool "512MBit (64MByte) total size"
-	depends on BOOT_ROM
-	help
-	  Use 512MBit (64MByte) of DDR total size
-
-config ONBOARD_DDR2_SIZE_1024MBIT
-	bool "1024MBit (128MByte) total size"
-	depends on BOOT_ROM
-	help
-	  Use 1024MBit (128MByte) of DDR total size
-
-config ONBOARD_DDR2_SIZE_2048MBIT
-	bool "2048MBit (256MByte) total size"
-	depends on BOOT_ROM
-	help
-	  Use 2048MBit (256MByte) of DDR total size
-
-endchoice
-
-choice
-	prompt "DDR2 chip width"
-
-config ONBOARD_DDR2_CHIP_WIDTH_8BIT
-	bool "8bit DDR chip width"
-	depends on BOOT_ROM
-	help
-	  Use DDR chips with 8bit width
-
-config ONBOARD_DDR2_CHIP_WIDTH_16BIT
-	bool "16bit DDR chip width"
-	depends on BOOT_ROM
-	help
-	  Use DDR chips with 16bit width
-
-endchoice
-
-choice
-	prompt "DDR2 bus width"
-
-config ONBOARD_DDR2_BUS_WIDTH_16BIT
-	bool "16bit DDR bus width"
-	depends on BOOT_ROM
-	help
-	  Use 16bit DDR bus width
-
-config ONBOARD_DDR2_BUS_WIDTH_32BIT
-	bool "32bit DDR bus width"
-	depends on BOOT_ROM
-	help
-	  Use 32bit DDR bus width
-
-endchoice
-
 config SUPPORTS_BOOT_RAM
 	bool
 
diff --git a/arch/mips/mach-mtmips/Makefile b/arch/mips/mach-mtmips/Makefile
index 1f3e65e8a5..72f0369030 100644
--- a/arch/mips/mach-mtmips/Makefile
+++ b/arch/mips/mach-mtmips/Makefile
@@ -1,8 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0+
 
 obj-y += cpu.o
+obj-y += ddr_init.o
+obj-y += ddr_cal.o
 
-ifndef CONFIG_SKIP_LOWLEVEL_INIT
-obj-y += ddr_calibrate.o
-obj-y += lowlevel_init.o
-endif
+obj-$(CONFIG_SOC_MT7628) += mt7628/
diff --git a/arch/mips/mach-mtmips/cpu.c b/arch/mips/mach-mtmips/cpu.c
index 7afc2c5940..459a9673eb 100644
--- a/arch/mips/mach-mtmips/cpu.c
+++ b/arch/mips/mach-mtmips/cpu.c
@@ -4,67 +4,17 @@
  */
 
 #include <common.h>
-#include <dm.h>
-#include <ram.h>
-#include <wdt.h>
-#include <asm/io.h>
+#include <malloc.h>
 #include <linux/io.h>
 #include <linux/sizes.h>
-#include "mt76xx.h"
 
-#define STR_LEN			6
-
-#ifdef CONFIG_BOOT_ROM
-int mach_cpu_init(void)
-{
-	ddr_calibrate();
-
-	return 0;
-}
-#endif
+DECLARE_GLOBAL_DATA_PTR;
 
 int dram_init(void)
 {
+#ifdef CONFIG_SKIP_LOWLEVEL_INIT
 	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, SZ_256M);
-
-	return 0;
-}
-
-int print_cpuinfo(void)
-{
-	static const char * const boot_str[] = { "PLL (3-Byte SPI Addr)",
-						 "PLL (4-Byte SPI Addr)",
-						 "XTAL (3-Byte SPI Addr)",
-						 "XTAL (4-Byte SPI Addr)" };
-	const void *blob = gd->fdt_blob;
-	void __iomem *sysc_base;
-	char buf[STR_LEN + 1];
-	fdt_addr_t base;
-	fdt_size_t size;
-	char *str;
-	int node;
-	u32 val;
-
-	/* Get system controller base address */
-	node = fdt_node_offset_by_compatible(blob, -1, "ralink,mt7620a-sysc");
-	if (node < 0)
-		return -FDT_ERR_NOTFOUND;
-
-	base = fdtdec_get_addr_size_auto_noparent(blob, node, "reg",
-						  0, &size, true);
-	if (base == FDT_ADDR_T_NONE)
-		return -EINVAL;
-
-	sysc_base = ioremap_nocache(base, size);
-
-	str = (char *)sysc_base + MT76XX_CHIPID_OFFS;
-	snprintf(buf, STR_LEN + 1, "%s", str);
-	val = readl(sysc_base + MT76XX_CHIP_REV_ID_OFFS);
-	printf("CPU:   %-*s Rev %ld.%ld - ", STR_LEN, buf,
-	       (val & GENMASK(11, 8)) >> 8, val & GENMASK(3, 0));
-
-	val = (readl(sysc_base + MT76XX_SYSCFG0_OFFS) & GENMASK(3, 1)) >> 1;
-	printf("Boot from %s\n", boot_str[val]);
+#endif
 
 	return 0;
 }
diff --git a/arch/mips/mach-mtmips/ddr_cal.c b/arch/mips/mach-mtmips/ddr_cal.c
new file mode 100644
index 0000000000..0ea7c7d5e1
--- /dev/null
+++ b/arch/mips/mach-mtmips/ddr_cal.c
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ *
+ * Author:  Weijie Gao <weijie.gao at mediatek.com>
+ */
+
+#include <common.h>
+#include <asm/addrspace.h>
+#include <asm/cacheops.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <mach/mc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define COARSE_MIN_START	6
+#define FINE_MIN_START		15
+#define COARSE_MAX_START	7
+#define FINE_MAX_START		0
+
+#define NUM_OF_CACHELINE	128
+#define TEST_PAT_SIZE		(NUM_OF_CACHELINE * CONFIG_SYS_CACHELINE_SIZE)
+
+#define INIT_DQS_VAL		((7 << DQS1_DELAY_COARSE_TUNING_S) | \
+				(4 << DQS1_DELAY_FINE_TUNING_S) | \
+				(7 << DQS0_DELAY_COARSE_TUNING_S) | \
+				(4 << DQS0_DELAY_FINE_TUNING_S))
+
+static inline void pref_op(int op, const volatile void *addr)
+{
+	__asm__ __volatile__("pref %0, 0(%1)" : : "i" (op), "r" (addr));
+}
+
+static inline int dqs_test_valid(void __iomem *memc, u32 memsize, u32 dqsval,
+				 u32 bias)
+{
+	u32 *nca, *ca;
+	u32 off;
+	int i;
+
+	for (off = 0; off < memsize - TEST_PAT_SIZE; off += (memsize >> 6)) {
+		nca = (u32 *)KSEG1ADDR(off);
+		ca = (u32 *)KSEG0ADDR(off);
+
+		writel(INIT_DQS_VAL, memc + MEMCTL_DDR_DQS_DLY_REG);
+		wmb();
+
+		for (i = 0; i < TEST_PAT_SIZE / sizeof(u32); i++)
+			ca[i] = 0x1f1f1f1f;
+
+		for (i = 0; i < TEST_PAT_SIZE / sizeof(u32); i++)
+			nca[i] = (u32)nca + i + bias;
+
+		writel(dqsval, memc + MEMCTL_DDR_DQS_DLY_REG);
+		wmb();
+
+		for (i = 0; i < TEST_PAT_SIZE; i += CONFIG_SYS_CACHELINE_SIZE)
+			mips_cache(HIT_INVALIDATE_D, (u8 *)ca + i);
+		wmb();
+
+		for (i = 0; i < TEST_PAT_SIZE; i += CONFIG_SYS_CACHELINE_SIZE)
+			pref_op(0, (u8 *)ca + i);
+
+		for (i = 0; i < TEST_PAT_SIZE / sizeof(u32); i++) {
+			if (ca[i] != (u32)nca + i + bias)
+				return -1;
+		}
+	}
+
+	return 0;
+}
+
+static inline u32 dqs_find_max(void __iomem *memc, u32 memsize, u32 initval,
+			       u32 maxval, u32 shift, u32 regval)
+{
+	u32 fieldval = initval, dqsval;
+
+	do {
+		dqsval = regval | (fieldval << shift);
+
+		if (dqs_test_valid(memc, memsize, dqsval, 3))
+			break;
+
+		fieldval++;
+	} while (fieldval <= maxval);
+
+	return fieldval;
+}
+
+static inline u32 dqs_find_min(void __iomem *memc, u32 memsize, u32 initval,
+			       u32 minval, u32 shift, u32 regval)
+{
+	u32 fieldval = initval, dqsval;
+
+	while (fieldval > minval) {
+		dqsval = regval | (fieldval << shift);
+
+		if (dqs_test_valid(memc, memsize, dqsval, 1)) {
+			fieldval++;
+			break;
+		}
+
+		fieldval--;
+	}
+
+	return fieldval;
+}
+
+void ddr_calibrate(void __iomem *memc, u32 memsize, u32 bw)
+{
+	u32 dqs_coarse_min, dqs_coarse_max, dqs_coarse_val;
+	u32 dqs_fine_min, dqs_fine_max, dqs_fine_val;
+	u32 dqs_coarse_min_limit, dqs_fine_min_limit;
+	u32 dlls, dqs_dll, ddr_cfg2_reg;
+	u32 dqs_dly_tmp, dqs_dly, test_dqs, shift;
+	u32 rem, mask;
+	int i;
+
+	/* Disable Self-refresh */
+	clrbits_32(memc + MEMCTL_DDR_SELF_REFRESH_REG, SR_AUTO_EN);
+
+	/* Save DDR_CFG2 and modify its DQS gating window */
+	ddr_cfg2_reg = readl(memc + MEMCTL_DDR_CFG2_REG);
+	mask = DQS0_GATING_WINDOW_M;
+	if (bw == IND_SDRAM_WIDTH_16BIT)
+		mask |= DQS1_GATING_WINDOW_M;
+	clrbits_32(memc + MEMCTL_DDR_CFG2_REG, mask);
+
+	/* Get minimum available DQS value */
+	dlls = readl(memc + MEMCTL_DLL_DBG_REG);
+	dlls = (dlls & MST_DLY_SEL_M) >> MST_DLY_SEL_S;
+
+	dqs_dll = dlls >> 4;
+	if (dqs_dll <= 8)
+		dqs_coarse_min_limit = 8 - dqs_dll;
+	else
+		dqs_coarse_min_limit = 0;
+
+	dqs_dll = dlls & 0xf;
+	if (dqs_dll <= 8)
+		dqs_fine_min_limit = 8 - dqs_dll;
+	else
+		dqs_fine_min_limit = 0;
+
+	/* Initial DQS register value */
+	dqs_dly = INIT_DQS_VAL;
+
+	/* Calibrate DQS0 and/or DQS1 */
+	for (i = 0; i < bw; i++) {
+		shift = i * 8;
+		dqs_dly &= ~(0xff << shift);
+
+		/* Find maximum DQS coarse-grain */
+		dqs_dly_tmp = dqs_dly | (0xf << shift);
+		dqs_coarse_max = dqs_find_max(memc, memsize, COARSE_MAX_START,
+					      0xf, 4 + shift, dqs_dly_tmp);
+
+		/* Find maximum DQS fine-grain */
+		dqs_dly_tmp = dqs_dly | (dqs_coarse_max << (4 + shift));
+		test_dqs = dqs_find_max(memc, memsize, FINE_MAX_START, 0xf,
+					shift, dqs_dly_tmp);
+
+		if (test_dqs == FINE_MAX_START) {
+			dqs_coarse_max--;
+			dqs_fine_max = 0xf;
+		} else {
+			dqs_fine_max = test_dqs - 1;
+		}
+
+		/* Find minimum DQS coarse-grain */
+		dqs_dly_tmp = dqs_dly;
+		dqs_coarse_min = dqs_find_min(memc, memsize, COARSE_MIN_START,
+					      dqs_coarse_min_limit, 4 + shift,
+					      dqs_dly_tmp);
+
+		/* Find minimum DQS fine-grain */
+		dqs_dly_tmp = dqs_dly | (dqs_coarse_min << (4 + shift));
+		test_dqs = dqs_find_min(memc, memsize, FINE_MIN_START,
+					dqs_fine_min_limit, shift, dqs_dly_tmp);
+
+		if (test_dqs == FINE_MIN_START + 1) {
+			dqs_coarse_min++;
+			dqs_fine_min = 0;
+		} else {
+			dqs_fine_min = test_dqs;
+		}
+
+		/* Calculate central DQS coarse/fine value */
+		dqs_coarse_val = (dqs_coarse_max + dqs_coarse_min) >> 1;
+		rem = (dqs_coarse_max + dqs_coarse_min) % 2;
+
+		dqs_fine_val = (rem * 4) + ((dqs_fine_max + dqs_fine_min) >> 1);
+		if (dqs_fine_val >= 0x10) {
+			dqs_coarse_val++;
+			dqs_fine_val -= 8;
+		}
+
+		/* Save current DQS value */
+		dqs_dly |= ((dqs_coarse_val << 4) | dqs_fine_val) << shift;
+	}
+
+	/* Set final DQS value */
+	writel(dqs_dly, memc + MEMCTL_DDR_DQS_DLY_REG);
+
+	/* Restore DDR_CFG2 */
+	writel(ddr_cfg2_reg, memc + MEMCTL_DDR_CFG2_REG);
+
+	/* Enable Self-refresh */
+	setbits_32(memc + MEMCTL_DDR_SELF_REFRESH_REG, SR_AUTO_EN);
+}
diff --git a/arch/mips/mach-mtmips/ddr_calibrate.c b/arch/mips/mach-mtmips/ddr_calibrate.c
deleted file mode 100644
index 3cd440804d..0000000000
--- a/arch/mips/mach-mtmips/ddr_calibrate.c
+++ /dev/null
@@ -1,309 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2018 Stefan Roese <sr at denx.de>
- *
- * This code is mostly based on the code extracted from this MediaTek
- * github repository:
- *
- * https://github.com/MediaTek-Labs/linkit-smart-uboot.git
- *
- * I was not able to find a specific license or other developers
- * copyrights here, so I can't add them here.
- *
- * Most functions in this file are copied from the MediaTek U-Boot
- * repository. Without any documentation, it was impossible to really
- * implement this differently. So its mostly a cleaned-up version of
- * the original code, with only support for the MT7628 / MT7688 SoC.
- */
-
-#include <common.h>
-#include <cpu_func.h>
-#include <linux/io.h>
-#include <asm/cacheops.h>
-#include <asm/io.h>
-#include "mt76xx.h"
-
-#define NUM_OF_CACHELINE	128
-#define MIN_START		6
-#define MIN_FINE_START		0xf
-#define MAX_START		7
-#define MAX_FINE_START		0x0
-
-#define CPU_FRAC_DIV		1
-
-#if defined(CONFIG_ONBOARD_DDR2_SIZE_256MBIT)
-#define DRAM_BUTTOM 0x02000000
-#endif
-#if defined(CONFIG_ONBOARD_DDR2_SIZE_512MBIT)
-#define DRAM_BUTTOM 0x04000000
-#endif
-#if defined(CONFIG_ONBOARD_DDR2_SIZE_1024MBIT)
-#define DRAM_BUTTOM 0x08000000
-#endif
-#if defined(CONFIG_ONBOARD_DDR2_SIZE_2048MBIT)
-#define DRAM_BUTTOM 0x10000000
-#endif
-
-static inline void cal_memcpy(void *src, void *dst, u32 size)
-{
-	u8 *psrc = (u8 *)src;
-	u8 *pdst = (u8 *)dst;
-	int i;
-
-	for (i = 0; i < size; i++, psrc++, pdst++)
-		*pdst = *psrc;
-}
-
-static inline void cal_memset(void *src, u8 pat, u32 size)
-{
-	u8 *psrc = (u8 *)src;
-	int i;
-
-	for (i = 0; i < size; i++, psrc++)
-		*psrc = pat;
-}
-
-#define pref_op(hint, addr)						\
-	__asm__ __volatile__(						\
-		".set	push\n"						\
-		".set	noreorder\n"					\
-		"pref	%0, %1\n"					\
-		".set	pop\n"						\
-		:							\
-		: "i" (hint), "R" (*(u8 *)(addr)))
-
-static inline void cal_patgen(u32 start_addr, u32 size, u32 bias)
-{
-	u32 *addr = (u32 *)start_addr;
-	int i;
-
-	for (i = 0; i < size; i++)
-		addr[i] = start_addr + i + bias;
-}
-
-static inline int test_loop(int k, int dqs, u32 test_dqs, u32 *coarse_dqs,
-			    u32 offs, u32 pat, u32 val)
-{
-	u32 nc_addr;
-	u32 *c_addr;
-	int i;
-
-	for (nc_addr = 0xa0000000;
-	     nc_addr < (0xa0000000 + DRAM_BUTTOM - NUM_OF_CACHELINE * 32);
-	     nc_addr += (DRAM_BUTTOM >> 6) + offs) {
-		writel(0x00007474, (void *)MT76XX_MEMCTRL_BASE + 0x64);
-		wmb();		/* Make sure store if finished */
-
-		c_addr = (u32 *)(nc_addr & 0xdfffffff);
-		cal_memset(((u8 *)c_addr), 0x1F, NUM_OF_CACHELINE * 32);
-		cal_patgen(nc_addr, NUM_OF_CACHELINE * 8, pat);
-
-		if (dqs > 0)
-			writel(0x00000074 |
-			       (((k == 1) ? coarse_dqs[dqs] : test_dqs) << 12) |
-			       (((k == 0) ? val : test_dqs) << 8),
-			       (void *)MT76XX_MEMCTRL_BASE + 0x64);
-		else
-			writel(0x00007400 |
-			       (((k == 1) ? coarse_dqs[dqs] : test_dqs) << 4) |
-			       (((k == 0) ? val : test_dqs) << 0),
-			       (void *)MT76XX_MEMCTRL_BASE + 0x64);
-		wmb();		/* Make sure store if finished */
-
-		invalidate_dcache_range((u32)c_addr,
-					(u32)c_addr +
-					NUM_OF_CACHELINE * 32);
-		wmb();		/* Make sure store if finished */
-
-		for (i = 0; i < NUM_OF_CACHELINE * 8; i++) {
-			if (i % 8 == 0)
-				pref_op(0, &c_addr[i]);
-		}
-
-		for (i = 0; i < NUM_OF_CACHELINE * 8; i++) {
-			if (c_addr[i] != nc_addr + i + pat)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-void ddr_calibrate(void)
-{
-	u32 min_coarse_dqs[2];
-	u32 max_coarse_dqs[2];
-	u32 min_fine_dqs[2];
-	u32 max_fine_dqs[2];
-	u32 coarse_dqs[2];
-	u32 fine_dqs[2];
-	int reg = 0, ddr_cfg2_reg;
-	int flag;
-	int i, k;
-	int dqs = 0;
-	u32 min_coarse_dqs_bnd, min_fine_dqs_bnd, coarse_dqs_dll, fine_dqs_dll;
-	u32 val;
-	u32 fdiv = 0, frac = 0;
-
-	/* Setup clock to run at full speed */
-	val = readl((void *)MT76XX_DYN_CFG0_REG);
-	fdiv = (u32)((val >> 8) & 0x0F);
-	if (CPU_FRAC_DIV < 1 || CPU_FRAC_DIV > 10)
-		frac = val & 0x0f;
-	else
-		frac = CPU_FRAC_DIV;
-
-	while (frac < fdiv) {
-		val = readl((void *)MT76XX_DYN_CFG0_REG);
-		fdiv = (val >> 8) & 0x0f;
-		fdiv--;
-		val &= ~(0x0f << 8);
-		val |= (fdiv << 8);
-		writel(val, (void *)MT76XX_DYN_CFG0_REG);
-		udelay(500);
-		val = readl((void *)MT76XX_DYN_CFG0_REG);
-		fdiv = (val >> 8) & 0x0f;
-	}
-
-	clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
-	ddr_cfg2_reg = readl((void *)MT76XX_MEMCTRL_BASE + 0x48);
-	clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x48,
-		     (0x3 << 28) | (0x3 << 26));
-
-	min_coarse_dqs[0] = MIN_START;
-	min_coarse_dqs[1] = MIN_START;
-	min_fine_dqs[0] = MIN_FINE_START;
-	min_fine_dqs[1] = MIN_FINE_START;
-	max_coarse_dqs[0] = MAX_START;
-	max_coarse_dqs[1] = MAX_START;
-	max_fine_dqs[0] = MAX_FINE_START;
-	max_fine_dqs[1] = MAX_FINE_START;
-	dqs = 0;
-
-	/* Add by KP, DQS MIN boundary */
-	reg = readl((void *)MT76XX_MEMCTRL_BASE + 0x20);
-	coarse_dqs_dll = (reg & 0xf00) >> 8;
-	fine_dqs_dll = (reg & 0xf0) >> 4;
-	if (coarse_dqs_dll <= 8)
-		min_coarse_dqs_bnd = 8 - coarse_dqs_dll;
-	else
-		min_coarse_dqs_bnd = 0;
-
-	if (fine_dqs_dll <= 8)
-		min_fine_dqs_bnd = 8 - fine_dqs_dll;
-	else
-		min_fine_dqs_bnd = 0;
-	/* DQS MIN boundary */
-
-DQS_CAL:
-
-	for (k = 0; k < 2; k++) {
-		u32 test_dqs;
-
-		if (k == 0)
-			test_dqs = MAX_START;
-		else
-			test_dqs = MAX_FINE_START;
-
-		do {
-			flag = test_loop(k, dqs, test_dqs, max_coarse_dqs,
-					 0x400, 0x3, 0xf);
-			if (flag == -1)
-				break;
-
-			test_dqs++;
-		} while (test_dqs <= 0xf);
-
-		if (k == 0) {
-			max_coarse_dqs[dqs] = test_dqs;
-		} else {
-			test_dqs--;
-
-			if (test_dqs == MAX_FINE_START - 1) {
-				max_coarse_dqs[dqs]--;
-				max_fine_dqs[dqs] = 0xf;
-			} else {
-				max_fine_dqs[dqs] = test_dqs;
-			}
-		}
-	}
-
-	for (k = 0; k < 2; k++) {
-		u32 test_dqs;
-
-		if (k == 0)
-			test_dqs = MIN_START;
-		else
-			test_dqs = MIN_FINE_START;
-
-		do {
-			flag = test_loop(k, dqs, test_dqs, min_coarse_dqs,
-					 0x480, 0x1, 0x0);
-			if (k == 0) {
-				if (flag == -1 ||
-				    test_dqs == min_coarse_dqs_bnd)
-					break;
-
-				test_dqs--;
-
-				if (test_dqs < min_coarse_dqs_bnd)
-					break;
-			} else {
-				if (flag == -1) {
-					test_dqs++;
-					break;
-				} else if (test_dqs == min_fine_dqs_bnd) {
-					break;
-				}
-
-				test_dqs--;
-
-				if (test_dqs < min_fine_dqs_bnd)
-					break;
-			}
-		} while (test_dqs >= 0);
-
-		if (k == 0) {
-			min_coarse_dqs[dqs] = test_dqs;
-		} else {
-			if (test_dqs == MIN_FINE_START + 1) {
-				min_coarse_dqs[dqs]++;
-				min_fine_dqs[dqs] = 0x0;
-			} else {
-				min_fine_dqs[dqs] = test_dqs;
-			}
-		}
-	}
-
-	if (dqs == 0) {
-		dqs = 1;
-		goto DQS_CAL;
-	}
-
-	for (i = 0; i < 2; i++) {
-		u32 temp;
-
-		coarse_dqs[i] = (max_coarse_dqs[i] + min_coarse_dqs[i]) >> 1;
-		temp =
-		    (((max_coarse_dqs[i] + min_coarse_dqs[i]) % 2) * 4) +
-		    ((max_fine_dqs[i] + min_fine_dqs[i]) >> 1);
-		if (temp >= 0x10) {
-			coarse_dqs[i]++;
-			fine_dqs[i] = (temp - 0x10) + 0x8;
-		} else {
-			fine_dqs[i] = temp;
-		}
-	}
-	reg = (coarse_dqs[1] << 12) | (fine_dqs[1] << 8) |
-		(coarse_dqs[0] << 4) | fine_dqs[0];
-
-	clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
-	writel(reg, (void *)MT76XX_MEMCTRL_BASE + 0x64);
-	writel(ddr_cfg2_reg, (void *)MT76XX_MEMCTRL_BASE + 0x48);
-	setbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
-
-	for (i = 0; i < 2; i++)
-		debug("[%02X%02X%02X%02X]", min_coarse_dqs[i],
-		      min_fine_dqs[i], max_coarse_dqs[i], max_fine_dqs[i]);
-	debug("\nDDR Calibration DQS reg = %08X\n", reg);
-}
diff --git a/arch/mips/mach-mtmips/ddr_init.c b/arch/mips/mach-mtmips/ddr_init.c
new file mode 100644
index 0000000000..cd355cc840
--- /dev/null
+++ b/arch/mips/mach-mtmips/ddr_init.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ *
+ * Author:  Weijie Gao <weijie.gao at mediatek.com>
+ */
+
+#include <common.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include <mach/ddr.h>
+#include <mach/mc.h>
+
+#define DDR_BW_TEST_PAT			0xaa5555aa
+
+static const u32 dram_size[] = {
+	[DRAM_8MB] = SZ_8M,
+	[DRAM_16MB] = SZ_16M,
+	[DRAM_32MB] = SZ_32M,
+	[DRAM_64MB] = SZ_64M,
+	[DRAM_128MB] = SZ_128M,
+	[DRAM_256MB] = SZ_256M,
+};
+
+static void dram_test_write(u32 addr, u32 val)
+{
+	volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
+
+	sync();
+	*target = val;
+	sync();
+}
+
+static u32 dram_test_read(u32 addr)
+{
+	volatile ulong *target = (volatile ulong *)(KSEG1 + addr);
+	u32 val;
+
+	sync();
+	val = *target;
+	sync();
+
+	return val;
+}
+
+static int dram_addr_test_bit(u32 bit)
+{
+	u32 val;
+
+	dram_test_write(0, 0);
+	dram_test_write(BIT(bit), DDR_BW_TEST_PAT);
+	val = dram_test_read(0);
+
+	if (val == DDR_BW_TEST_PAT)
+		return 1;
+
+	return 0;
+}
+
+static void mc_ddr_init(void __iomem *memc, const struct mc_ddr_cfg *cfg,
+			u32 dq_dly, u32 dqs_dly, mc_reset_t mc_reset, u32 bw)
+{
+	u32 val;
+
+	mc_reset(1);
+	__udelay(200);
+	mc_reset(0);
+
+	clrbits_32(memc + MEMCTL_SDRAM_CFG1_REG, RBC_MAPPING);
+
+	writel(cfg->cfg2, memc + MEMCTL_DDR_CFG2_REG);
+	writel(cfg->cfg3, memc + MEMCTL_DDR_CFG3_REG);
+	writel(cfg->cfg4, memc + MEMCTL_DDR_CFG4_REG);
+	writel(dq_dly, memc + MEMCTL_DDR_DQ_DLY_REG);
+	writel(dqs_dly, memc + MEMCTL_DDR_DQS_DLY_REG);
+
+	writel(cfg->cfg0, memc + MEMCTL_DDR_CFG0_REG);
+
+	val = cfg->cfg1;
+	if (bw) {
+		val &= ~IND_SDRAM_WIDTH_M;
+		val |= (bw << IND_SDRAM_WIDTH_S) & IND_SDRAM_WIDTH_M;
+	}
+
+	writel(val, memc + MEMCTL_DDR_CFG1_REG);
+
+	clrsetbits_32(memc + MEMCTL_PWR_SAVE_CNT_REG, SR_TAR_CNT_M,
+		      1 << SR_TAR_CNT_S);
+
+	setbits_32(memc + MEMCTL_DDR_SELF_REFRESH_REG, SR_AUTO_EN);
+}
+
+void ddr1_init(struct mc_ddr_init_param *param)
+{
+	enum mc_dram_size sz;
+	u32 bw = 0;
+
+	/* First initialization, determine bus width */
+	mc_ddr_init(param->memc, &param->cfgs[DRAM_8MB], param->dq_dly,
+		    param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
+
+	/* Test bus width */
+	dram_test_write(0, DDR_BW_TEST_PAT);
+	if (dram_test_read(0) == DDR_BW_TEST_PAT)
+		bw = IND_SDRAM_WIDTH_16BIT;
+	else
+		bw = IND_SDRAM_WIDTH_8BIT;
+
+	/* Second initialization, determine DDR capacity */
+	mc_ddr_init(param->memc, &param->cfgs[DRAM_128MB], param->dq_dly,
+		    param->dqs_dly, param->mc_reset, bw);
+
+	if (dram_addr_test_bit(9)) {
+		sz = DRAM_8MB;
+	} else {
+		if (dram_addr_test_bit(10)) {
+			if (dram_addr_test_bit(23))
+				sz = DRAM_16MB;
+			else
+				sz = DRAM_32MB;
+		} else {
+			if (dram_addr_test_bit(24))
+				sz = DRAM_64MB;
+			else
+				sz = DRAM_128MB;
+		}
+	}
+
+	/* Final initialization, with DDR calibration */
+	mc_ddr_init(param->memc, &param->cfgs[sz], param->dq_dly,
+		    param->dqs_dly, param->mc_reset, bw);
+
+	/* Return actual DDR configuration */
+	param->memsize = dram_size[sz];
+	param->bus_width = bw;
+}
+
+void ddr2_init(struct mc_ddr_init_param *param)
+{
+	enum mc_dram_size sz;
+	u32 bw = 0;
+
+	/* First initialization, determine bus width */
+	mc_ddr_init(param->memc, &param->cfgs[DRAM_32MB], param->dq_dly,
+		    param->dqs_dly, param->mc_reset, IND_SDRAM_WIDTH_16BIT);
+
+	/* Test bus width */
+	dram_test_write(0, DDR_BW_TEST_PAT);
+	if (dram_test_read(0) == DDR_BW_TEST_PAT)
+		bw = IND_SDRAM_WIDTH_16BIT;
+	else
+		bw = IND_SDRAM_WIDTH_8BIT;
+
+	/* Second initialization, determine DDR capacity */
+	mc_ddr_init(param->memc, &param->cfgs[DRAM_256MB], param->dq_dly,
+		    param->dqs_dly, param->mc_reset, bw);
+
+	if (bw == IND_SDRAM_WIDTH_16BIT) {
+		if (dram_addr_test_bit(10)) {
+			sz = DRAM_32MB;
+		} else {
+			if (dram_addr_test_bit(24)) {
+				if (dram_addr_test_bit(27))
+					sz = DRAM_64MB;
+				else
+					sz = DRAM_128MB;
+			} else {
+				sz = DRAM_256MB;
+			}
+		}
+	} else {
+		if (dram_addr_test_bit(23)) {
+			sz = DRAM_32MB;
+		} else {
+			if (dram_addr_test_bit(24)) {
+				if (dram_addr_test_bit(27))
+					sz = DRAM_64MB;
+				else
+					sz = DRAM_128MB;
+			} else {
+				sz = DRAM_256MB;
+			}
+		}
+	}
+
+	/* Final initialization, with DDR calibration */
+	mc_ddr_init(param->memc, &param->cfgs[sz], param->dq_dly,
+		    param->dqs_dly, param->mc_reset, bw);
+
+	/* Return actual DDR configuration */
+	param->memsize = dram_size[sz];
+	param->bus_width = bw;
+}
diff --git a/arch/mips/mach-mtmips/include/mach/ddr.h b/arch/mips/mach-mtmips/include/mach/ddr.h
new file mode 100644
index 0000000000..f92198137b
--- /dev/null
+++ b/arch/mips/mach-mtmips/include/mach/ddr.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ *
+ * Author:  Weijie Gao <weijie.gao at mediatek.com>
+ */
+
+#ifndef _MTMIPS_DDR_H_
+#define _MTMIPS_DDR_H_
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+enum mc_dram_size {
+	DRAM_8MB,
+	DRAM_16MB,
+	DRAM_32MB,
+	DRAM_64MB,
+	DRAM_128MB,
+	DRAM_256MB,
+
+	__DRAM_SZ_MAX
+};
+
+struct mc_ddr_cfg {
+	u32 cfg0;
+	u32 cfg1;
+	u32 cfg2;
+	u32 cfg3;
+	u32 cfg4;
+};
+
+typedef void (*mc_reset_t)(int assert);
+
+struct mc_ddr_init_param {
+	void __iomem *memc;
+
+	u32 dq_dly;
+	u32 dqs_dly;
+
+	const struct mc_ddr_cfg *cfgs;
+	mc_reset_t mc_reset;
+
+	u32 memsize;
+	u32 bus_width;
+};
+
+void ddr1_init(struct mc_ddr_init_param *param);
+void ddr2_init(struct mc_ddr_init_param *param);
+void ddr_calibrate(void __iomem *memc, u32 memsize, u32 bw);
+
+#endif /* _MTMIPS_DDR_H_ */
diff --git a/arch/mips/mach-mtmips/include/mach/mc.h b/arch/mips/mach-mtmips/include/mach/mc.h
new file mode 100644
index 0000000000..d7d623a63b
--- /dev/null
+++ b/arch/mips/mach-mtmips/include/mach/mc.h
@@ -0,0 +1,180 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ *
+ * Author:  Weijie Gao <weijie.gao at mediatek.com>
+ */
+
+#ifndef _MTMIPS_MC_H_
+#define _MTMIPS_MC_H_
+
+#define MEMCTL_SDRAM_CFG0_REG		0x00
+#define DIS_CLK_GT			0x80000000
+#define CLK_SLEW_S			29
+#define CLK_SLEW_M			0x60000000
+#define TWR				0x10000000
+#define TMRD_S				24
+#define TMRD_M				0xf000000
+#define TRFC_S				20
+#define TRFC_M				0xf00000
+#define TCAS_S				16
+#define TCAS_M				0x30000
+#define TRAS_S				12
+#define TRAS_M				0xf000
+#define TRCD_S				8
+#define TRCD_M				0x300
+#define TRC_S				4
+#define TRC_M				0xf0
+#define TRP_S				0
+#define TRP_M				0x03
+
+#define MEMCTL_SDRAM_CFG1_REG		0x04
+#define SDRAM_INIT_START		0x80000000
+#define SDRAM_INIT_DONE			0x40000000
+#define RBC_MAPPING			0x20000000
+#define PWR_DOWN_EN			0x10000000
+#define PWR_DOWN_MODE			0x8000000
+#define SDRAM_WIDTH			0x1000000
+#define NUMCOLS_S			20
+#define NUMCOLS_M			0x300000
+#define NUMROWS_S			16
+#define NUMROWS_M			0x30000
+#define TREFR_S				0
+#define TREFR_M				0xffff
+
+#define MEMCTL_DDR_SELF_REFRESH_REG	0x10
+#define ODT_SRC_SEL_S			24
+#define ODT_SRC_SEL_M			0xf000000
+#define ODT_OFF_DLY_S			20
+#define ODT_OFF_DLY_M			0xf00000
+#define ODT_ON_DLY_S			16
+#define ODT_ON_DLY_M			0xf0000
+#define SR_AUTO_EN			0x10
+#define SRACK_B				0x02
+#define SRREQ_B				0x01
+
+#define MEMCTL_PWR_SAVE_CNT_REG		0x14
+#define PD_CNT_S			24
+#define PD_CNT_M			0xff000000
+#define SR_TAR_CNT_S			0
+#define SR_TAR_CNT_M			0xffffff
+
+#define MEMCTL_DLL_DBG_REG		0x20
+#define TDC_STABLE_S			12
+#define TDC_STABLE_M			0x3f000
+#define MST_DLY_SEL_S			4
+#define MST_DLY_SEL_M			0xff0
+#define CURR_STATE_S			1
+#define CURR_STATE_M			0x06
+#define ADLL_LOCK_DONE			0x01
+
+#define MEMCTL_DDR_CFG0_REG		0x40
+#define T_RRD_S				28
+#define T_RRD_M				0xf0000000
+#define T_RAS_S				23
+#define T_RAS_M				0xf800000
+#define T_RP_S				19
+#define T_RP_M				0x780000
+#define T_RFC_S				13
+#define T_RFC_M				0x7e000
+#define T_REFI_S			0
+#define T_REFI_M			0x1fff
+
+#define MEMCTL_DDR_CFG1_REG		0x44
+#define T_WTR_S				28
+#define T_WTR_M				0xf0000000
+#define T_RTP_S				24
+#define T_RTP_M				0xf000000
+#define USER_DATA_WIDTH			0x200000
+#define IND_SDRAM_SIZE_S		18
+#define IND_SDRAM_SIZE_M		0x1c0000
+#define IND_SDRAM_SIZE_8MB		1
+#define IND_SDRAM_SIZE_16MB		2
+#define IND_SDRAM_SIZE_32MB		3
+#define IND_SDRAM_SIZE_64MB		4
+#define IND_SDRAM_SIZE_128MB		5
+#define IND_SDRAM_SIZE_256MB		6
+#define IND_SDRAM_WIDTH_S		16
+#define IND_SDRAM_WIDTH_M		0x30000
+#define IND_SDRAM_WIDTH_8BIT		1
+#define IND_SDRAM_WIDTH_16BIT		2
+#define EXT_BANK_S			14
+#define EXT_BANK_M			0xc000
+#define TOTAL_SDRAM_WIDTH_S		12
+#define TOTAL_SDRAM_WIDTH_M		0x3000
+#define T_WR_S				8
+#define T_WR_M				0xf00
+#define T_MRD_S				4
+#define T_MRD_M				0xf0
+#define T_RCD_S				0
+#define T_RCD_M				0x0f
+
+#define MEMCTL_DDR_CFG2_REG		0x48
+#define REGE				0x80000000
+#define DDR2_MODE			0x40000000
+#define DQS0_GATING_WINDOW_S		28
+#define DQS0_GATING_WINDOW_M		0x30000000
+#define DQS1_GATING_WINDOW_S		26
+#define DQS1_GATING_WINDOW_M		0xc000000
+#define PD				0x1000
+#define WR_S				9
+#define WR_M				0xe00
+#define DLLRESET			0x100
+#define TESTMODE			0x80
+#define CAS_LATENCY_S			4
+#define CAS_LATENCY_M			0x70
+#define BURST_TYPE			0x08
+#define BURST_LENGTH_S			0
+#define BURST_LENGTH_M			0x07
+
+#define MEMCTL_DDR_CFG3_REG		0x4c
+#define Q_OFF				0x1000
+#define RDOS				0x800
+#define DIS_DIFF_DQS			0x400
+#define OCD_S				7
+#define OCD_M				0x380
+#define RTT1				0x40
+#define ADDITIVE_LATENCY_S		3
+#define ADDITIVE_LATENCY_M		0x38
+#define RTT0				0x04
+#define DS				0x02
+#define DLL				0x01
+
+#define MEMCTL_DDR_CFG4_REG		0x50
+#define FAW_S				0
+#define FAW_M				0x0f
+
+#define MEMCTL_DDR_DQ_DLY_REG		0x60
+#define DQ1_DELAY_SEL_S			24
+#define DQ1_DELAY_SEL_M			0xff000000
+#define DQ0_DELAY_SEL_S			16
+#define DQ0_DELAY_SEL_M			0xff0000
+#define DQ1_DELAY_COARSE_TUNING_S	12
+#define DQ1_DELAY_COARSE_TUNING_M	0xf000
+#define DQ1_DELAY_FINE_TUNING_S		8
+#define DQ1_DELAY_FINE_TUNING_M		0xf00
+#define DQ0_DELAY_COARSE_TUNING_S	4
+#define DQ0_DELAY_COARSE_TUNING_M	0xf0
+#define DQ0_DELAY_FINE_TUNING_S		0
+#define DQ0_DELAY_FINE_TUNING_M		0x0f
+
+#define MEMCTL_DDR_DQS_DLY_REG		0x64
+#define DQS1_DELAY_SEL_S		24
+#define DQS1_DELAY_SEL_M		0xff000000
+#define DQS0_DELAY_SEL_S		16
+#define DQS0_DELAY_SEL_M		0xff0000
+#define DQS1_DELAY_COARSE_TUNING_S	12
+#define DQS1_DELAY_COARSE_TUNING_M	0xf000
+#define DQS1_DELAY_FINE_TUNING_S	8
+#define DQS1_DELAY_FINE_TUNING_M	0xf00
+#define DQS0_DELAY_COARSE_TUNING_S	4
+#define DQS0_DELAY_COARSE_TUNING_M	0xf0
+#define DQS0_DELAY_FINE_TUNING_S	0
+#define DQS0_DELAY_FINE_TUNING_M	0x0f
+
+#define MEMCTL_DDR_DLL_SLV_REG		0x68
+#define DLL_SLV_UPDATE_MODE		0x100
+#define DQS_DLY_SEL_EN			0x80
+#define DQ_DLY_SEL_EN			0x01
+
+#endif /* _MTMIPS_MC_H_ */
diff --git a/arch/mips/mach-mtmips/lowlevel_init.S b/arch/mips/mach-mtmips/lowlevel_init.S
deleted file mode 100644
index aa707e0de6..0000000000
--- a/arch/mips/mach-mtmips/lowlevel_init.S
+++ /dev/null
@@ -1,328 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * (c) 2018 Stefan Roese <sr at denx.de>
- *
- * This code is mostly based on the code extracted from this MediaTek
- * github repository:
- *
- * https://github.com/MediaTek-Labs/linkit-smart-uboot.git
- *
- * I was not able to find a specific license or other developers
- * copyrights here, so I can't add them here.
- */
-
-#include <config.h>
-#include <asm/regdef.h>
-#include <asm/mipsregs.h>
-#include <asm/addrspace.h>
-#include <asm/asm.h>
-#include "mt76xx.h"
-
-#ifndef BIT
-#define BIT(nr)			(1 << (nr))
-#endif
-
-#define DELAY_USEC(us)		((us) / 100)
-
-#define DDR_CFG1_CHIP_WIDTH_MASK (0x3 << 16)
-#define DDR_CFG1_BUS_WIDTH_MASK	(0x3 << 12)
-
-#if defined(CONFIG_ONBOARD_DDR2_SIZE_256MBIT)
-#define DDR_CFG1_SIZE_VAL	0x222e2323
-#define DDR_CFG4_SIZE_VAL	7
-#endif
-#if defined(CONFIG_ONBOARD_DDR2_SIZE_512MBIT)
-#define DDR_CFG1_SIZE_VAL	0x22322323
-#define DDR_CFG4_SIZE_VAL	9
-#endif
-#if defined(CONFIG_ONBOARD_DDR2_SIZE_1024MBIT)
-#define DDR_CFG1_SIZE_VAL	0x22362323
-#define DDR_CFG4_SIZE_VAL	9
-#endif
-#if defined(CONFIG_ONBOARD_DDR2_SIZE_2048MBIT)
-#define DDR_CFG1_SIZE_VAL	0x223a2323
-#define DDR_CFG4_SIZE_VAL	9
-#endif
-
-#if defined(CONFIG_ONBOARD_DDR2_CHIP_WIDTH_8BIT)
-#define DDR_CFG1_CHIP_WIDTH_VAL	(0x1 << 16)
-#endif
-#if defined(CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT)
-#define DDR_CFG1_CHIP_WIDTH_VAL	(0x2 << 16)
-#endif
-
-#if defined(CONFIG_ONBOARD_DDR2_BUS_WIDTH_16BIT)
-#define DDR_CFG1_BUS_WIDTH_VAL	(0x2 << 12)
-#endif
-#if defined(CONFIG_ONBOARD_DDR2_BUS_WIDTH_32BIT)
-#define DDR_CFG1_BUS_WIDTH_VAL	(0x3 << 12)
-#endif
-
-	.set noreorder
-
-LEAF(lowlevel_init)
-
-	/* Load base addresses as physical addresses for later usage */
-	li	s0, CKSEG1ADDR(MT76XX_SYSCTL_BASE)
-	li	s1, CKSEG1ADDR(MT76XX_MEMCTRL_BASE)
-	li	s2, CKSEG1ADDR(MT76XX_RGCTRL_BASE)
-
-	/* polling CPLL is ready */
-	li	t1, DELAY_USEC(1000000)
-	la	t5, MT76XX_ROM_STATUS_REG
-1:
-	lw	t2, 0(t5)
-	andi	t2, t2, 0x1
-	bnez	t2, CPLL_READY
-	subu	t1, t1, 1
-	bgtz	t1, 1b
-	nop
-	la      t0, MT76XX_CLKCFG0_REG
-	lw      t3, 0(t0)
-	ori	t3, t3, 0x1
-	sw	t3, 0(t0)
-	b	CPLL_DONE
-	nop
-CPLL_READY:
-	la	t0, MT76XX_CLKCFG0_REG
-	lw	t1, 0(t0)
-	li	t2, ~0x0c
-	and	t1, t1, t2
-	ori	t1, t1, 0xc
-	sw	t1, 0(t0)
-	la	t0, MT76XX_DYN_CFG0_REG
-	lw	t3, 0(t0)
-	li	t5, ~((0x0f << 8) | (0x0f << 0))
-	and	t3, t3, t5
-	li	t5, (10 << 8) | (1 << 0)
-	or	t3, t3, t5
-	sw	t3, 0(t0)
-	la	t0, MT76XX_CLKCFG0_REG
-	lw	t3, 0(t0)
-	li	t4, ~0x0F
-	and     t3, t3, t4
-	ori	t3, t3, 0xc
-	sw	t3, 0(t0)
-	lw	t3, 0(t0)
-	ori	t3, t3, 0x08
-	sw	t3, 0(t0)
-
-CPLL_DONE:
-	/* Reset MC */
-	lw	t2, 0x34(s0)
-	ori	t2, BIT(10)
-	sw	t2, 0x34(s0)
-	nop
-
-	/*
-	 * SDR and DDR initialization: delay 200us
-	 */
-	li	t0, DELAY_USEC(200 + 40)
-	li	t1, 0x1
-1:
-	sub	t0, t0, t1
-	bnez	t0, 1b
-	nop
-
-	/* set DRAM IO PAD for MT7628IC */
-	/* DDR LDO Enable  */
-	lw	t4, 0x100(s2)
-	li	t2, BIT(31)
-	or	t4, t4, t2
-	sw	t4, 0x100(s2)
-	lw	t4, 0x10c(s2)
-	j	LDO_1P8V
-	nop
-LDO_1P8V:
-	li	t2, ~BIT(6)
-	and	t4, t4, t2
-	sw	t4, 0x10c(s2)
-	j	DDRLDO_SOFT_START
-LDO_2P5V:
-	/* suppose external DDR1 LDO 2.5V */
-	li	t2, BIT(6)
-	or	t4, t4, t2
-	sw	t4, 0x10c(s2)
-
-DDRLDO_SOFT_START:
-	lw	t2, 0x10c(s2)
-	li	t3, BIT(16)
-	or	t2, t2, t3
-	sw	t2, 0x10c(s2)
-	li	t3, DELAY_USEC(250*50)
-LDO_DELAY:
-	subu	t3, t3, 1
-	bnez	t3, LDO_DELAY
-	nop
-
-	lw	t2, 0x10c(s2)
-	li	t3, BIT(18)
-	or	t2, t2, t3
-	sw	t2, 0x10c(s2)
-
-SET_RG_BUCK_FPWM:
-	lw	t2, 0x104(s2)
-	ori	t2, t2, BIT(10)
-	sw	t2, 0x104(s2)
-
-DDR_PAD_CFG:
-	/* clean CLK PAD */
-	lw	t2, 0x704(s2)
-	li	t8, 0xfffff0f0
-	and	t2, t2, t8
-	/* clean CMD PAD */
-	lw	t3, 0x70c(s2)
-	li	t8, 0xfffff0f0
-	and	t3, t3, t8
-	/* clean DQ IPAD */
-	lw	t4, 0x710(s2)
-	li	t8, 0xfffff8ff
-	and	t4, t4, t8
-	/* clean DQ OPAD */
-	lw	t5, 0x714(s2)
-	li	t8, 0xfffff0f0
-	and	t5, t5, t8
-	/* clean DQS IPAD */
-	lw	t6, 0x718(s2)
-	li	t8, 0xfffff8ff
-	and	t6, t6, t8
-	/* clean DQS OPAD */
-	lw	t7, 0x71c(s2)
-	li	t8, 0xfffff0f0
-	and	t7, t7, t8
-
-	lw	t9, 0xc(s0)
-	srl	t9, t9, 16
-	andi	t9, t9, 0x1
-	bnez	t9, MT7628_AN_DDR1_PAD
-MT7628_KN_PAD:
-	li	t8, 0x00000303
-	or	t2, t2, t8
-	or	t3, t3, t8
-	or	t5, t5, t8
-	or	t7, t7, t8
-	li	t8, 0x00000000
-	or	t4, t4, t8
-	or	t6, t6, t8
-	j	SET_PAD_CFG
-MT7628_AN_DDR1_PAD:
-	lw	t1, 0x10(s0)
-	andi	t1, t1, 0x1
-	beqz	t1, MT7628_AN_DDR2_PAD
-	li	t8, 0x00000c0c
-	or	t2, t2, t8
-	li	t8, 0x00000202
-	or	t3, t3, t8
-	li	t8, 0x00000707
-	or	t5, t5, t8
-	li	t8, 0x00000c0c
-	or	t7, t7, t8
-	li	t8, 0x00000000
-	or	t4, t4, t8
-	or	t6, t6, t8
-	j	SET_PAD_CFG
-MT7628_AN_DDR2_PAD:
-	li	t8, 0x00000c0c
-	or	t2, t2, t8
-	li	t8, 0x00000202
-	or	t3, t3, t8
-	li	t8, 0x00000404
-	or	t5, t5, t8
-	li	t8, 0x00000c0c
-	or	t7, t7, t8
-	li	t8, 0x00000000		/* ODT off */
-	or	t4, t4, t8
-	or	t6, t6, t8
-
-SET_PAD_CFG:
-	sw	t2, 0x704(s2)
-	sw	t3, 0x70c(s2)
-	sw	t4, 0x710(s2)
-	sw	t5, 0x714(s2)
-	sw	t6, 0x718(s2)
-	sw	t7, 0x71c(s2)
-
-	/*
-	 * DDR initialization: reset pin to 0
-	 */
-	lw	t2, 0x34(s0)
-	and	t2, ~BIT(10)
-	sw	t2, 0x34(s0)
-	nop
-
-	/*
-	 * DDR initialization: wait til reg DDR_CFG1 bit 21 equal to 1 (ready)
-	 */
-DDR_READY:
-	li	t1, DDR_CFG1_REG
-	lw	t0, 0(t1)
-	nop
-	and	t2, t0, BIT(21)
-	beqz	t2, DDR_READY
-	nop
-
-	/*
-	 * DDR initialization
-	 *
-	 * Only DDR2 supported right now. DDR2 support can be added, once
-	 * boards using it will get added to mainline U-Boot.
-	 */
-	li	t1, DDR_CFG2_REG
-	lw	t0, 0(t1)
-	nop
-	and	t0, ~BIT(30)
-	and	t0, ~(7 << 4)
-	or	t0, (4 << 4)
-	or	t0, BIT(30)
-	or	t0, BIT(11)
-	sw	t0, 0(t1)
-	nop
-
-	li	t1, DDR_CFG3_REG
-	lw	t2, 0(t1)
-	/* Disable ODT; reference board ok, ev board fail */
-	and	t2, ~BIT(6)
-	or	t2, BIT(2)
-	li	t0, DDR_CFG4_REG
-	lw	t1, 0(t0)
-	li	t2, ~(0x01f | 0x0f0)
-	and	t1, t1, t2
-	ori	t1, t1, DDR_CFG4_SIZE_VAL
-	sw	t1, 0(t0)
-	nop
-
-	/*
-	 * DDR initialization: config size and width on reg DDR_CFG1
-	 */
-	li	t6, DDR_CFG1_SIZE_VAL
-
-	and	t6, ~DDR_CFG1_CHIP_WIDTH_MASK
-	or	t6, DDR_CFG1_CHIP_WIDTH_VAL
-
-	/* CONFIG DDR_CFG1[13:12] about TOTAL WIDTH */
-	and	t6, ~DDR_CFG1_BUS_WIDTH_MASK
-	or	t6, DDR_CFG1_BUS_WIDTH_VAL
-
-	li	t5, DDR_CFG1_REG
-	sw	t6, 0(t5)
-	nop
-
-	/*
-	 * DDR: enable self auto refresh for power saving
-	 * enable it by default for both RAM and ROM version (for CoC)
-	 */
-	lw	t1, 0x14(s1)
-	nop
-	and	t1, 0xff000000
-	or	t1, 0x01
-	sw	t1, 0x14(s1)
-	nop
-	lw	t1, 0x10(s1)
-	nop
-	or	t1, 0x10
-	sw	t1, 0x10(s1)
-	nop
-
-	jr	ra
-	nop
-	END(lowlevel_init)
diff --git a/arch/mips/mach-mtmips/mt7628/Makefile b/arch/mips/mach-mtmips/mt7628/Makefile
new file mode 100644
index 0000000000..db62e90d77
--- /dev/null
+++ b/arch/mips/mach-mtmips/mt7628/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += lowlevel_init.o
+obj-y += init.o
+obj-y += ddr.o
diff --git a/arch/mips/mach-mtmips/mt7628/ddr.c b/arch/mips/mach-mtmips/mt7628/ddr.c
new file mode 100644
index 0000000000..861a675beb
--- /dev/null
+++ b/arch/mips/mach-mtmips/mt7628/ddr.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ *
+ * Author:  Weijie Gao <weijie.gao at mediatek.com>
+ */
+
+#include <common.h>
+#include <asm/addrspace.h>
+#include <linux/bitops.h>
+#include <linux/sizes.h>
+#include <linux/io.h>
+#include <mach/ddr.h>
+#include <mach/mc.h>
+#include "mt7628.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* DDR2 DQ_DLY */
+#define DDR2_DQ_DLY \
+				((0x8 << DQ1_DELAY_COARSE_TUNING_S) | \
+				(0x2 << DQ1_DELAY_FINE_TUNING_S) | \
+				(0x8 << DQ0_DELAY_COARSE_TUNING_S) | \
+				(0x2 << DQ0_DELAY_FINE_TUNING_S))
+
+/* DDR2 DQS_DLY */
+#define DDR2_DQS_DLY \
+				((0x8 << DQS1_DELAY_COARSE_TUNING_S) | \
+				(0x3 << DQS1_DELAY_FINE_TUNING_S) | \
+				(0x8 << DQS0_DELAY_COARSE_TUNING_S) | \
+				(0x3 << DQS0_DELAY_FINE_TUNING_S))
+
+const struct mc_ddr_cfg ddr1_cfgs_200mhz[] = {
+	[DRAM_8MB]   = { 0x34A1EB94, 0x20262324, 0x28000033, 0x00000002, 0x00000000 },
+	[DRAM_16MB]  = { 0x34A1EB94, 0x202A2324, 0x28000033, 0x00000002, 0x00000000 },
+	[DRAM_32MB]  = { 0x34A1E5CA, 0x202E2324, 0x28000033, 0x00000002, 0x00000000 },
+	[DRAM_64MB]  = { 0x3421E5CA, 0x20322324, 0x28000033, 0x00000002, 0x00000000 },
+	[DRAM_128MB] = { 0x241B05CA, 0x20362334, 0x28000033, 0x00000002, 0x00000000 },
+};
+
+const struct mc_ddr_cfg ddr1_cfgs_160mhz[] = {
+	[DRAM_8MB]   = { 0x239964A1, 0x20262323, 0x00000033, 0x00000002, 0x00000000 },
+	[DRAM_16MB]  = { 0x239964A1, 0x202A2323, 0x00000033, 0x00000002, 0x00000000 },
+	[DRAM_32MB]  = { 0x239964A1, 0x202E2323, 0x00000033, 0x00000002, 0x00000000 },
+	[DRAM_64MB]  = { 0x239984A1, 0x20322323, 0x00000033, 0x00000002, 0x00000000 },
+	[DRAM_128MB] = { 0x239AB4A1, 0x20362333, 0x00000033, 0x00000002, 0x00000000 },
+};
+
+const struct mc_ddr_cfg ddr2_cfgs_200mhz[] = {
+	[DRAM_32MB]  = { 0x2519E2E5, 0x222E2323, 0x68000C43, 0x00000452, 0x0000000A },
+	[DRAM_64MB]  = { 0x249AA2E5, 0x22322323, 0x68000C43, 0x00000452, 0x0000000A },
+	[DRAM_128MB] = { 0x249B42E5, 0x22362323, 0x68000C43, 0x00000452, 0x0000000A },
+	[DRAM_256MB] = { 0x249CE2E5, 0x223A2323, 0x68000C43, 0x00000452, 0x0000000A },
+};
+
+const struct mc_ddr_cfg ddr2_cfgs_160mhz[] = {
+	[DRAM_32MB]  = { 0x23918250, 0x222E2322, 0x40000A43, 0x00000452, 0x00000006 },
+	[DRAM_64MB]  = { 0x239A2250, 0x22322322, 0x40000A43, 0x00000452, 0x00000008 },
+	[DRAM_128MB] = { 0x2392A250, 0x22362322, 0x40000A43, 0x00000452, 0x00000008 },
+	[DRAM_256MB] = { 0x24140250, 0x223A2322, 0x40000A43, 0x00000452, 0x00000008 },
+};
+
+static void mt7628_memc_reset(int assert)
+{
+	void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
+
+	if (assert)
+		setbits_32(sysc + SYSCTL_RSTCTL_REG, MC_RST);
+	else
+		clrbits_32(sysc + SYSCTL_RSTCTL_REG, MC_RST);
+}
+
+static void mt7628_ddr_pad_ldo_config(int ddr_type, int pkg_type)
+{
+	void __iomem *rgc = ioremap_nocache(RGCTL_BASE, RGCTL_SIZE);
+	u32 ck_pad1, cmd_pad1, dq_pad0, dq_pad1, dqs_pad0, dqs_pad1;
+
+	setbits_32(rgc + RGCTL_PMU_G0_REG, PMU_CFG_EN);
+
+	if (ddr_type == DRAM_DDR1)
+		setbits_32(rgc + RGCTL_PMU_G3_REG, RG_DDRLDO_VOSEL);
+	else
+		clrbits_32(rgc + RGCTL_PMU_G3_REG, RG_DDRLDO_VOSEL);
+
+	setbits_32(rgc + RGCTL_PMU_G3_REG, NI_DDRLDO_EN);
+
+	__udelay(250 * 50);
+
+	setbits_32(rgc + RGCTL_PMU_G3_REG, NI_DDRLDO_STB);
+	setbits_32(rgc + RGCTL_PMU_G1_REG, RG_BUCK_FPWM);
+
+	ck_pad1 = readl(rgc + RGCTL_DDR_PAD_CK_G1_REG);
+	cmd_pad1 = readl(rgc + RGCTL_DDR_PAD_CMD_G1_REG);
+	dq_pad0 = readl(rgc + RGCTL_DDR_PAD_DQ_G0_REG);
+	dq_pad1 = readl(rgc + RGCTL_DDR_PAD_DQ_G1_REG);
+	dqs_pad0 = readl(rgc + RGCTL_DDR_PAD_DQS_G0_REG);
+	dqs_pad1 = readl(rgc + RGCTL_DDR_PAD_DQS_G1_REG);
+
+	ck_pad1 &= ~(DRVP_M | DRVN_M);
+	cmd_pad1 &= ~(DRVP_M | DRVN_M);
+	dq_pad0 &= ~RTT_M;
+	dq_pad1 &= ~(DRVP_M | DRVN_M);
+	dqs_pad0 &= ~RTT_M;
+	dqs_pad1 &= ~(DRVP_M | DRVN_M);
+
+	if (pkg_type == PKG_ID_KN) {
+		ck_pad1 |= (3 << DRVP_S) | (3 << DRVN_S);
+		cmd_pad1 |= (3 << DRVP_S) | (3 << DRVN_S);
+		dq_pad1 |= (3 << DRVP_S) | (3 << DRVN_S);
+		dqs_pad1 |= (3 << DRVP_S) | (3 << DRVN_S);
+	} else {
+		ck_pad1 |= (12 << DRVP_S) | (12 << DRVN_S);
+		cmd_pad1 |= (2 << DRVP_S) | (2 << DRVN_S);
+		dqs_pad1 |= (12 << DRVP_S) | (12 << DRVN_S);
+		if (ddr_type == DRAM_DDR1)
+			dq_pad1 |= (7 << DRVP_S) | (7 << DRVN_S);
+		else
+			dq_pad1 |= (4 << DRVP_S) | (4 << DRVN_S);
+	}
+
+	writel(ck_pad1, rgc + RGCTL_DDR_PAD_CK_G1_REG);
+	writel(cmd_pad1, rgc + RGCTL_DDR_PAD_CMD_G1_REG);
+	writel(dq_pad0, rgc + RGCTL_DDR_PAD_DQ_G0_REG);
+	writel(dq_pad1, rgc + RGCTL_DDR_PAD_DQ_G1_REG);
+	writel(dqs_pad0, rgc + RGCTL_DDR_PAD_DQS_G0_REG);
+	writel(dqs_pad1, rgc + RGCTL_DDR_PAD_DQS_G1_REG);
+}
+
+void mt7628_ddr_init(void)
+{
+	void __iomem *sysc;
+	int ddr_type, pkg_type, lspd;
+	struct mc_ddr_init_param param;
+
+	sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
+	ddr_type = readl(sysc + SYSCTL_SYSCFG0_REG) & DRAM_TYPE;
+	pkg_type = !!(readl(sysc + SYSCTL_CHIP_REV_ID_REG) & PKG_ID);
+	lspd = readl(sysc + SYSCTL_CLKCFG0_REG) &
+	       (CPU_PLL_FROM_BBP | CPU_PLL_FROM_XTAL);
+
+	mt7628_memc_reset(1);
+	__udelay(200);
+
+	mt7628_ddr_pad_ldo_config(ddr_type, pkg_type);
+
+	param.memc = ioremap_nocache(MEMCTL_BASE, MEMCTL_SIZE);
+	param.dq_dly = DDR2_DQ_DLY;
+	param.dqs_dly = DDR2_DQS_DLY;
+	param.mc_reset = mt7628_memc_reset;
+	param.memsize = 0;
+	param.bus_width = 0;
+
+	if (pkg_type == PKG_ID_KN)
+		ddr_type = DRAM_DDR1;
+
+	if (ddr_type == DRAM_DDR1) {
+		if (lspd)
+			param.cfgs = ddr1_cfgs_160mhz;
+		else
+			param.cfgs = ddr1_cfgs_200mhz;
+		ddr1_init(&param);
+	} else {
+		if (lspd)
+			param.cfgs = ddr2_cfgs_160mhz;
+		else
+			param.cfgs = ddr2_cfgs_200mhz;
+		ddr2_init(&param);
+	}
+
+	ddr_calibrate(param.memc, param.memsize, param.bus_width);
+
+	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, SZ_256M);
+}
diff --git a/arch/mips/mach-mtmips/mt7628/init.c b/arch/mips/mach-mtmips/mt7628/init.c
new file mode 100644
index 0000000000..77d1f2ea0d
--- /dev/null
+++ b/arch/mips/mach-mtmips/mt7628/init.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ *
+ * Author:  Weijie Gao <weijie.gao at mediatek.com>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/uclass.h>
+#include <dt-bindings/clock/mt7628-clk.h>
+#include <linux/io.h>
+#include "mt7628.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void set_init_timer_freq(void)
+{
+	void __iomem *sysc;
+	u32 bs, val, timer_freq_post;
+
+	sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
+
+	/* We can't use the clk driver as the DM has not been initialized yet */
+	bs = readl(sysc + SYSCTL_SYSCFG0_REG);
+	if ((bs & XTAL_FREQ_SEL) == XTAL_25MHZ) {
+		gd->arch.timer_freq = 25000000;
+		timer_freq_post = 575000000;
+	} else {
+		gd->arch.timer_freq = 40000000;
+		timer_freq_post = 580000000;
+	}
+
+	val = readl(sysc + SYSCTL_CLKCFG0_REG);
+	if (!(val & (CPU_PLL_FROM_BBP | CPU_PLL_FROM_XTAL)))
+		gd->arch.timer_freq = timer_freq_post;
+}
+
+void mt7628_init(void)
+{
+	set_init_timer_freq();
+
+	mt7628_ddr_init();
+}
+
+int print_cpuinfo(void)
+{
+	void __iomem *sysc;
+	struct udevice *clkdev;
+	u32 val, ver, eco, pkg, ddr, chipmode, ee;
+	ulong cpu_clk, bus_clk, xtal_clk, timer_freq;
+	struct clk clk;
+	int ret;
+
+	sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
+
+	val = readl(sysc + SYSCTL_CHIP_REV_ID_REG);
+	ver = (val & VER_M) >> VER_S;
+	eco = (val & ECO_M) >> ECO_S;
+	pkg = !!(val & PKG_ID);
+
+	val = readl(sysc + SYSCTL_SYSCFG0_REG);
+	ddr = val & DRAM_TYPE;
+	chipmode = (val & CHIP_MODE_M) >> CHIP_MODE_S;
+
+	val = readl(sysc + SYSCTL_EFUSE_CFG_REG);
+	ee = val & EFUSE_MT7688;
+
+	printf("CPU:   MediaTek MT%u%c ver:%u eco:%u\n",
+	       ee ? 7688 : 7628, pkg ? 'A' : 'K', ver, eco);
+
+	printf("Boot:  DDR%s, SPI-NOR %u-Byte Addr, CPU clock from %s\n",
+	       ddr ? "" : "2", chipmode & 0x01 ? 4 : 3,
+	       chipmode & 0x02 ? "XTAL" : "CPLL");
+
+	ret = uclass_get_device_by_driver(UCLASS_CLK, DM_GET_DRIVER(mt7628_clk),
+					  &clkdev);
+	if (ret)
+		return ret;
+
+	clk.dev = clkdev;
+
+	clk.id = CLK_CPU;
+	cpu_clk = clk_get_rate(&clk);
+
+	clk.id = CLK_SYS;
+	bus_clk = clk_get_rate(&clk);
+
+	clk.id = CLK_XTAL;
+	xtal_clk = clk_get_rate(&clk);
+
+	clk.id = CLK_MIPS_CNT;
+	timer_freq = clk_get_rate(&clk);
+
+	/* Set final timer frequency */
+	if (timer_freq)
+		gd->arch.timer_freq = timer_freq;
+
+	printf("Clock: CPU: %luMHz, Bus: %luMHz, XTAL: %luMHz\n",
+	       cpu_clk / 1000000, bus_clk / 1000000, xtal_clk / 1000000);
+
+	return 0;
+}
+
+ulong notrace get_tbclk(void)
+{
+	return gd->arch.timer_freq;
+}
diff --git a/arch/mips/mach-mtmips/mt7628/lowlevel_init.S b/arch/mips/mach-mtmips/mt7628/lowlevel_init.S
new file mode 100644
index 0000000000..eeab2ca825
--- /dev/null
+++ b/arch/mips/mach-mtmips/mt7628/lowlevel_init.S
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ *
+ * Author:  Weijie Gao <weijie.gao at mediatek.com>
+ */
+
+#include <config.h>
+#include <asm-offsets.h>
+#include <asm/cacheops.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/asm.h>
+#include "mt7628.h"
+
+/* Set temporary stack address range */
+#ifndef CONFIG_SYS_INIT_SP_ADDR
+#define CONFIG_SYS_INIT_SP_ADDR	(CONFIG_SYS_SDRAM_BASE + \
+				CONFIG_SYS_INIT_SP_OFFSET)
+#endif
+
+#define CACHE_STACK_SIZE	0x4000
+#define CACHE_STACK_BASE	(CONFIG_SYS_INIT_SP_ADDR - CACHE_STACK_SIZE)
+
+#define DELAY_USEC(us)		((58 * (us)) / 3)
+
+	.set noreorder
+
+LEAF(mips_sram_init)
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	/* Setup CPU PLL */
+	li	t0, DELAY_USEC(1000000)
+	li	t1, KSEG1ADDR(SYSCTL_BASE + SYSCTL_ROM_STATUS_REG)
+	li	t2, KSEG1ADDR(SYSCTL_BASE + SYSCTL_CLKCFG0_REG)
+
+_check_rom_status:
+	lw	t3, 0(t1)
+	andi	t3, t3, 1
+	bnez	t3, _rom_normal
+	subu	t0, t0, 1
+	bnez	t0, _check_rom_status
+	 nop
+
+	lw	t3, 0(t2)
+	ori	t3, (CPU_PLL_FROM_BBP | CPU_PLL_FROM_XTAL)
+	xori	t3, CPU_PLL_FROM_BBP
+	b	_cpu_pll_done
+	 nop
+
+_rom_normal:
+	lw	t3, 0(t2)
+	ori	t3, (CPU_PLL_FROM_BBP | CPU_PLL_FROM_XTAL | \
+		    DIS_BBP_SLEEP | EN_BBP_CLK)
+	xori	t3, (CPU_PLL_FROM_BBP | CPU_PLL_FROM_XTAL)
+
+_cpu_pll_done:
+	sw	t3, 0(t2)
+
+	li	t2, KSEG1ADDR(RBUSCTL_BASE + RBUSCTL_DYN_CFG0_REG)
+	lw	t3, 0(t2)
+	ori	t3, t3, (CPU_FDIV_M | CPU_FFRAC_M)
+	xori	t3, t3, (CPU_FDIV_M | CPU_FFRAC_M)
+	ori	t3, t3, ((1 << CPU_FDIV_S) | (1 << CPU_FFRAC_S))
+	sw	t3, 0(t2)
+
+	/* Clear WST & SPR bits in ErrCtl */
+	mfc0	t0, CP0_ECC
+	ins	t0, zero, 30, 2
+	mtc0	t0, CP0_ECC
+	ehb
+
+	/* Simply initialize I-Cache */
+	li	a0, 0
+	li	a1, CONFIG_SYS_ICACHE_SIZE
+
+	mtc0	zero, CP0_TAGLO		/* Zero to DDataLo */
+
+1:	cache	INDEX_STORE_TAG_I, 0(a0)
+	addiu	a0, CONFIG_SYS_ICACHE_LINE_SIZE
+	bne	a0, a1, 1b
+	 nop
+
+	/* Simply initialize D-Cache */
+	li	a0, 0
+	li	a1, CONFIG_SYS_DCACHE_SIZE
+
+	mtc0	zero, CP0_TAGLO, 2
+
+2:	cache	INDEX_STORE_TAG_D, 0(a0)
+	addiu	a0, CONFIG_SYS_DCACHE_LINE_SIZE
+	bne	a0, a1, 2b
+	 nop
+
+	/* Set KSEG0 Cachable */
+	mfc0	t0, CP0_CONFIG
+	and	t0, t0, MIPS_CONF_IMPL
+	or	t0, t0, CONF_CM_CACHABLE_NONCOHERENT
+	mtc0	t0, CP0_CONFIG
+	ehb
+
+	/* Lock D-Cache */
+	PTR_LI	a0, CACHE_STACK_BASE		/* D-Cache lock base */
+	li	a1, CACHE_STACK_SIZE		/* D-Cache lock size */
+	li	a2, 0x1ffff800			/* Mask of DTagLo[PTagLo] */
+
+3:
+	/* Lock one cacheline */
+	and	t0, a0, a2
+	ori	t0, 0xe0			/* Valid & Dirty & Lock bits */
+	mtc0	t0, CP0_TAGLO, 2		/* Write to DTagLo */
+	ehb
+	cache	INDEX_STORE_TAG_D, 0(a0)
+
+	addiu	a0, CONFIG_SYS_DCACHE_LINE_SIZE
+	sub	a1, CONFIG_SYS_DCACHE_LINE_SIZE
+	bnez	a1, 3b
+	 nop
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+	jr	ra
+	 nop
+	END(mips_sram_init)
+
+NESTED(lowlevel_init, 0, ra)
+	/* Save ra and do real lowlevel initialization */
+	move	s0, ra
+
+	PTR_LA	t9, mt7628_init
+	jalr	t9
+	 nop
+
+	move	ra, s0
+
+	/* Write back data in locked cache to DRAM */
+	PTR_LI	a0, CACHE_STACK_BASE		/* D-Cache unlock base */
+	li	a1, CACHE_STACK_SIZE		/* D-Cache unlock size */
+
+1:
+	cache	HIT_WRITEBACK_INV_D, 0(a0)
+	addiu	a0, CONFIG_SYS_DCACHE_LINE_SIZE
+	sub	a1, CONFIG_SYS_DCACHE_LINE_SIZE
+	bnez	a1, 1b
+	 nop
+
+	/* Set KSEG0 Uncached */
+	mfc0	t0, CP0_CONFIG
+	and	t0, t0, MIPS_CONF_IMPL
+	or	t0, t0, CONF_CM_UNCACHED
+	mtc0	t0, CP0_CONFIG
+	ehb
+
+	jr	ra
+	 nop
+	END(lowlevel_init)
diff --git a/arch/mips/mach-mtmips/mt7628/mt7628.h b/arch/mips/mach-mtmips/mt7628/mt7628.h
new file mode 100644
index 0000000000..b363c03480
--- /dev/null
+++ b/arch/mips/mach-mtmips/mt7628/mt7628.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ *
+ * Author:  Weijie Gao <weijie.gao at mediatek.com>
+ */
+
+#ifndef _MT7628_H_
+#define _MT7628_H_
+
+#define SYSCTL_BASE			0x10000000
+#define SYSCTL_SIZE			0x100
+#define MEMCTL_BASE			0x10000300
+#define MEMCTL_SIZE			0x100
+#define RBUSCTL_BASE			0x10000400
+#define RBUSCTL_SIZE			0x100
+#define RGCTL_BASE			0x10001000
+#define RGCTL_SIZE			0x800
+
+#define SYSCTL_EFUSE_CFG_REG		0x08
+#define EFUSE_MT7688			0x100000
+
+#define SYSCTL_CHIP_REV_ID_REG		0x0c
+#define PKG_ID				0x10000
+#define PKG_ID_AN			1
+#define PKG_ID_KN			0
+#define VER_S				8
+#define VER_M				0xf00
+#define ECO_S				0
+#define ECO_M				0x0f
+
+#define SYSCTL_SYSCFG0_REG		0x10
+#define XTAL_FREQ_SEL			0x40
+#define XTAL_40MHZ			1
+#define XTAL_25MHZ			0
+#define CHIP_MODE_S			1
+#define CHIP_MODE_M			0x0e
+#define DRAM_TYPE			0x01
+#define DRAM_DDR1			1
+#define DRAM_DDR2			0
+
+#define SYSCTL_ROM_STATUS_REG		0x28
+
+#define SYSCTL_CLKCFG0_REG		0x2c
+#define DIS_BBP_SLEEP			0x08
+#define EN_BBP_CLK			0x04
+#define CPU_PLL_FROM_BBP		0x02
+#define CPU_PLL_FROM_XTAL		0x01
+
+#define SYSCTL_RSTCTL_REG		0x34
+#define MC_RST				0x400
+
+#define RBUSCTL_DYN_CFG0_REG		0x40
+#define CPU_FDIV_S			8
+#define CPU_FDIV_M			0xf00
+#define CPU_FFRAC_S			0
+#define CPU_FFRAC_M			0x0f
+
+#define RGCTL_PMU_G0_REG		0x100
+#define PMU_CFG_EN			0x80000000
+
+#define RGCTL_PMU_G1_REG		0x104
+#define RG_BUCK_FPWM			0x02
+
+#define RGCTL_PMU_G3_REG		0x10c
+#define NI_DDRLDO_STB			0x40000
+#define NI_DDRLDO_EN			0x10000
+#define RG_DDRLDO_VOSEL			0x40
+
+#define RGCTL_DDR_PAD_CK_G0_REG		0x700
+#define RGCTL_DDR_PAD_CMD_G0_REG	0x708
+#define RGCTL_DDR_PAD_DQ_G0_REG		0x710
+#define RGCTL_DDR_PAD_DQS_G0_REG	0x718
+#define RTT_S				8
+#define RTT_M				0x700
+
+#define RGCTL_DDR_PAD_CK_G1_REG		0x704
+#define RGCTL_DDR_PAD_CMD_G1_REG	0x70c
+#define RGCTL_DDR_PAD_DQ_G1_REG		0x714
+#define RGCTL_DDR_PAD_DQS_G1_REG	0x71c
+#define DRVP_S				0
+#define DRVP_M				0x0f
+#define DRVN_S				8
+#define DRVN_M				0xf00
+
+#ifndef __ASSEMBLY__
+void mt7628_ddr_init(void);
+#endif
+
+#endif /* _MT7628_H_ */
diff --git a/arch/mips/mach-mtmips/mt76xx.h b/arch/mips/mach-mtmips/mt76xx.h
deleted file mode 100644
index 17473ea8f1..0000000000
--- a/arch/mips/mach-mtmips/mt76xx.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (C) 2018 Stefan Roese <sr at denx.de>
- */
-
-#ifndef __MT76XX_H
-#define __MT76XX_H
-
-#define MT76XX_SYSCTL_BASE	0x10000000
-
-#define MT76XX_CHIPID_OFFS	0x00
-#define MT76XX_CHIP_REV_ID_OFFS	0x0c
-#define MT76XX_SYSCFG0_OFFS	0x10
-
-#define MT76XX_MEMCTRL_BASE	(MT76XX_SYSCTL_BASE + 0x0300)
-#define MT76XX_RGCTRL_BASE	(MT76XX_SYSCTL_BASE + 0x1000)
-
-#define MT76XX_ROM_STATUS_REG	(MT76XX_SYSCTL_BASE + 0x0028)
-#define MT76XX_CLKCFG0_REG	(MT76XX_SYSCTL_BASE + 0x002c)
-#define MT76XX_DYN_CFG0_REG	(MT76XX_SYSCTL_BASE + 0x0440)
-
-#define DDR_CFG1_REG		(MT76XX_MEMCTRL_BASE + 0x44)
-#define DDR_CFG2_REG		(MT76XX_MEMCTRL_BASE + 0x48)
-#define DDR_CFG3_REG		(MT76XX_MEMCTRL_BASE + 0x4c)
-#define DDR_CFG4_REG		(MT76XX_MEMCTRL_BASE + 0x50)
-
-#ifndef __ASSEMBLY__
-/* Prototypes */
-void ddr_calibrate(void);
-#endif
-
-#endif
diff --git a/configs/gardena-smart-gateway-mt7688-ram_defconfig b/configs/gardena-smart-gateway-mt7688-ram_defconfig
index 9324d9bb91..41e52a92cc 100644
--- a/configs/gardena-smart-gateway-mt7688-ram_defconfig
+++ b/configs/gardena-smart-gateway-mt7688-ram_defconfig
@@ -8,6 +8,7 @@ CONFIG_SYS_BOOTCOUNT_ADDR=0xb000006c
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_ARCH_MTMIPS=y
 CONFIG_BOARD_GARDENA_SMART_GATEWAY_MT7688=y
+CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y
 # CONFIG_MIPS_BOOT_ENV_LEGACY is not set
 CONFIG_MIPS_BOOT_FDT=y
 CONFIG_ENV_VARS_UBOOT_CONFIG=y
@@ -69,7 +70,6 @@ CONFIG_MT7628_ETH=y
 CONFIG_PHY=y
 CONFIG_SPI=y
 CONFIG_MT7621_SPI=y
-CONFIG_SYSRESET_SYSCON=y
 CONFIG_WDT=y
 CONFIG_WDT_MT7621=y
 CONFIG_LZMA=y
diff --git a/configs/gardena-smart-gateway-mt7688_defconfig b/configs/gardena-smart-gateway-mt7688_defconfig
index 64b2c6a1c3..7cd06cb014 100644
--- a/configs/gardena-smart-gateway-mt7688_defconfig
+++ b/configs/gardena-smart-gateway-mt7688_defconfig
@@ -9,8 +9,7 @@ CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_ARCH_MTMIPS=y
 CONFIG_BOARD_GARDENA_SMART_GATEWAY_MT7688=y
 CONFIG_BOOT_ROM=y
-CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y
-CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT=y
+CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y
 # CONFIG_MIPS_BOOT_ENV_LEGACY is not set
 CONFIG_MIPS_BOOT_FDT=y
 CONFIG_ENV_VARS_UBOOT_CONFIG=y
@@ -72,7 +71,6 @@ CONFIG_MT7628_ETH=y
 CONFIG_PHY=y
 CONFIG_SPI=y
 CONFIG_MT7621_SPI=y
-CONFIG_SYSRESET_SYSCON=y
 CONFIG_WDT=y
 CONFIG_WDT_MT7621=y
 CONFIG_LZMA=y
diff --git a/configs/linkit-smart-7688-ram_defconfig b/configs/linkit-smart-7688-ram_defconfig
index 6d2e9e4298..6d8969aacb 100644
--- a/configs/linkit-smart-7688-ram_defconfig
+++ b/configs/linkit-smart-7688-ram_defconfig
@@ -6,6 +6,7 @@ CONFIG_NR_DRAM_BANKS=1
 CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_ARCH_MTMIPS=y
 CONFIG_BOARD_LINKIT_SMART_7688=y
+CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y
 # CONFIG_MIPS_BOOT_ENV_LEGACY is not set
 CONFIG_MIPS_BOOT_FDT=y
 CONFIG_FIT=y
@@ -53,7 +54,6 @@ CONFIG_PHY=y
 CONFIG_MT76X8_USB_PHY=y
 CONFIG_SPI=y
 CONFIG_MT7621_SPI=y
-CONFIG_SYSRESET_SYSCON=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
diff --git a/configs/linkit-smart-7688_defconfig b/configs/linkit-smart-7688_defconfig
index 28c8be2d53..9ddee9a861 100644
--- a/configs/linkit-smart-7688_defconfig
+++ b/configs/linkit-smart-7688_defconfig
@@ -7,8 +7,7 @@ CONFIG_ENV_SECT_SIZE=0x10000
 CONFIG_ARCH_MTMIPS=y
 CONFIG_BOARD_LINKIT_SMART_7688=y
 CONFIG_BOOT_ROM=y
-CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y
-CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT=y
+CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y
 # CONFIG_MIPS_BOOT_ENV_LEGACY is not set
 CONFIG_MIPS_BOOT_FDT=y
 CONFIG_FIT=y
@@ -57,7 +56,6 @@ CONFIG_PHY=y
 CONFIG_MT76X8_USB_PHY=y
 CONFIG_SPI=y
 CONFIG_MT7621_SPI=y
-CONFIG_SYSRESET_SYSCON=y
 CONFIG_USB=y
 CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
-- 
2.17.1


More information about the U-Boot mailing list