mips: Add basic MediaTek MT7620/88 support
authorStefan Roese <sr@denx.de>
Wed, 5 Sep 2018 13:12:35 +0000 (15:12 +0200)
committerDaniel Schwierzeck <daniel.schwierzeck@gmail.com>
Sat, 22 Sep 2018 19:18:33 +0000 (21:18 +0200)
This patch adds basic support for the MediaTek MT7620/88 SoCs. Parts of
the code is copied from the MediaTek GitHub repository:

https://github.com/MediaTek-Labs/linkit-smart-uboot.git

The mt7628a.dtsi file is imported from Linux v4.17.

Support for the LinkIt Smart 7688 module and the Gardena Smart Gateway
both based on the MT7688 will be added in further patches.

Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/dts/mt7628a.dtsi [new file with mode: 0644]
arch/mips/mach-mt7620/Kconfig [new file with mode: 0644]
arch/mips/mach-mt7620/Makefile [new file with mode: 0644]
arch/mips/mach-mt7620/cpu.c [new file with mode: 0644]
arch/mips/mach-mt7620/ddr_calibrate.c [new file with mode: 0644]
arch/mips/mach-mt7620/lowlevel_init.S [new file with mode: 0644]
arch/mips/mach-mt7620/mt76xx.h [new file with mode: 0644]

index 30fb9bff748f8b25e43ef12fa072980fdfad3c22..10b55c914e689718522199aefee79ea2b525434d 100644 (file)
@@ -69,6 +69,21 @@ config ARCH_BMIPS
        select SYSRESET
        imply CMD_DM
 
+config ARCH_MT7620
+       bool "Support MT7620/7688 SoCs"
+       imply CMD_DM
+       select DISPLAY_CPUINFO
+       select DM
+       select DM_SERIAL
+       imply DM_SPI
+       imply DM_SPI_FLASH
+       select MIPS_TUNE_24KC
+       select OF_CONTROL
+       select ROM_EXCEPTION_VECTORS
+       select SUPPORTS_CPU_MIPS32_R1
+       select SUPPORTS_CPU_MIPS32_R2
+       select SUPPORTS_LITTLE_ENDIAN
+
 config MACH_PIC32
        bool "Support Microchip PIC32"
        select DM
@@ -121,6 +136,7 @@ source "board/qemu-mips/Kconfig"
 source "arch/mips/mach-ath79/Kconfig"
 source "arch/mips/mach-bmips/Kconfig"
 source "arch/mips/mach-pic32/Kconfig"
+source "arch/mips/mach-mt7620/Kconfig"
 
 if MIPS
 
index a36f5f1fb6b2baec196f89338bf318116a93be2b..802244a06e5d5e0fd8d2ba8a68a2b471b079d32d 100644 (file)
@@ -14,6 +14,7 @@ libs-y += arch/mips/lib/
 machine-$(CONFIG_ARCH_ATH79) += ath79
 machine-$(CONFIG_ARCH_BMIPS) += bmips
 machine-$(CONFIG_MACH_PIC32) += pic32
+machine-$(CONFIG_ARCH_MT7620) += mt7620
 
 machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y))
 libs-y += $(machdirs)
diff --git a/arch/mips/dts/mt7628a.dtsi b/arch/mips/dts/mt7628a.dtsi
new file mode 100644 (file)
index 0000000..d00f528
--- /dev/null
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "ralink,mt7628a-soc";
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       compatible = "mti,mips24KEc";
+                       device_type = "cpu";
+                       reg = <0>;
+               };
+       };
+
+       resetc: reset-controller {
+               compatible = "ralink,rt2880-reset";
+               #reset-cells = <1>;
+       };
+
+       cpuintc: interrupt-controller {
+               #address-cells = <0>;
+               #interrupt-cells = <1>;
+               interrupt-controller;
+               compatible = "mti,cpu-interrupt-controller";
+       };
+
+       palmbus@10000000 {
+               compatible = "palmbus", "simple-bus";
+               reg = <0x10000000 0x200000>;
+               ranges = <0x0 0x10000000 0x1FFFFF>;
+
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               sysc: system-controller@0 {
+                       compatible = "ralink,mt7620a-sysc", "syscon";
+                       reg = <0x0 0x100>;
+               };
+
+               intc: interrupt-controller@200 {
+                       compatible = "ralink,rt2880-intc";
+                       reg = <0x200 0x100>;
+
+                       interrupt-controller;
+                       #interrupt-cells = <1>;
+
+                       resets = <&resetc 9>;
+                       reset-names = "intc";
+
+                       interrupt-parent = <&cpuintc>;
+                       interrupts = <2>;
+
+                       ralink,intc-registers = <0x9c 0xa0
+                                                0x6c 0xa4
+                                                0x80 0x78>;
+               };
+
+               memory-controller@300 {
+                       compatible = "ralink,mt7620a-memc";
+                       reg = <0x300 0x100>;
+               };
+
+               spi0: spi@b00 {
+                       compatible = "ralink,mt7621-spi";
+                       reg = <0xb00 0x40>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               uart0: uartlite@c00 {
+                       compatible = "ns16550a";
+                       reg = <0xc00 0x100>;
+
+                       resets = <&resetc 12>;
+                       reset-names = "uart0";
+
+                       interrupt-parent = <&intc>;
+                       interrupts = <20>;
+
+                       reg-shift = <2>;
+               };
+
+               uart1: uart1@d00 {
+                       compatible = "ns16550a";
+                       reg = <0xd00 0x100>;
+
+                       resets = <&resetc 19>;
+                       reset-names = "uart1";
+
+                       interrupt-parent = <&intc>;
+                       interrupts = <21>;
+
+                       reg-shift = <2>;
+               };
+
+               uart2: uart2@e00 {
+                       compatible = "ns16550a";
+                       reg = <0xe00 0x100>;
+
+                       resets = <&resetc 20>;
+                       reset-names = "uart2";
+
+                       interrupt-parent = <&intc>;
+                       interrupts = <22>;
+
+                       reg-shift = <2>;
+               };
+       };
+
+       usb_phy: usb-phy@10120000 {
+               compatible = "mediatek,mt7628-usbphy";
+               reg = <0x10120000 0x1000>;
+
+               #phy-cells = <0>;
+
+               ralink,sysctl = <&sysc>;
+               resets = <&resetc 22 &resetc 25>;
+               reset-names = "host", "device";
+       };
+
+       ehci@101c0000 {
+               compatible = "generic-ehci";
+               reg = <0x101c0000 0x1000>;
+
+               phys = <&usb_phy>;
+               phy-names = "usb";
+
+               interrupt-parent = <&intc>;
+               interrupts = <18>;
+       };
+};
diff --git a/arch/mips/mach-mt7620/Kconfig b/arch/mips/mach-mt7620/Kconfig
new file mode 100644 (file)
index 0000000..396fbd0
--- /dev/null
@@ -0,0 +1,113 @@
+menu "MediaTek MIPS platforms"
+       depends on ARCH_MT7620
+
+config SYS_MALLOC_F_LEN
+       default 0x1000
+
+config SYS_SOC
+       default "mt7620" if SOC_MT7620
+
+choice
+       prompt "MediaTek MIPS SoC select"
+
+config SOC_MT7620
+       bool "MT7620/8"
+       select MIPS_L1_CACHE_SHIFT_5
+       help
+         This supports MediaTek MIPS MT7620 family.
+
+endchoice
+
+choice
+       prompt "Board select"
+
+endchoice
+
+choice
+       prompt "Boot mode"
+
+config BOOT_RAM
+       bool "RAM boot"
+       depends on SUPPORTS_BOOT_RAM
+       help
+         This builds an image that is linked to a RAM address. It can be used
+         for booting from CFE via TFTP using an ELF image, but it can also be
+         booted from RAM by other bootloaders using a BIN image.
+
+config BOOT_ROM
+       bool "ROM boot"
+       depends on SUPPORTS_BOOT_RAM
+       help
+         This builds an image that is linked to a ROM address. It can be
+         used as main bootloader image which is programmed onto the onboard
+         flash storage (SPI NOR).
+
+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
+
+endmenu
diff --git a/arch/mips/mach-mt7620/Makefile b/arch/mips/mach-mt7620/Makefile
new file mode 100644 (file)
index 0000000..1f3e65e
--- /dev/null
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += cpu.o
+
+ifndef CONFIG_SKIP_LOWLEVEL_INIT
+obj-y += ddr_calibrate.o
+obj-y += lowlevel_init.o
+endif
diff --git a/arch/mips/mach-mt7620/cpu.c b/arch/mips/mach-mt7620/cpu.c
new file mode 100644 (file)
index 0000000..457f09f
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <asm/io.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
+
+int dram_init(void)
+{
+       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]);
+
+       return 0;
+}
diff --git a/arch/mips/mach-mt7620/ddr_calibrate.c b/arch/mips/mach-mt7620/ddr_calibrate.c
new file mode 100644 (file)
index 0000000..75763c4
--- /dev/null
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@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 <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-mt7620/lowlevel_init.S b/arch/mips/mach-mt7620/lowlevel_init.S
new file mode 100644 (file)
index 0000000..1a50f16
--- /dev/null
@@ -0,0 +1,322 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (c) 2018 Stefan Roese <sr@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:
+       /*
+        * 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-mt7620/mt76xx.h b/arch/mips/mach-mt7620/mt76xx.h
new file mode 100644 (file)
index 0000000..17473ea
--- /dev/null
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@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