[U-Boot] [PATCH 1/4] mips: Add basic MediaTek MT7620/88 support

Daniel Schwierzeck daniel.schwierzeck at gmail.com
Tue Aug 7 15:44:06 UTC 2018


2018-08-06 17:11 GMT+02:00 Stefan Roese <sr at denx.de>:
> 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
>
> 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 at denx.de>
> Cc: Daniel Schwierzeck <daniel.schwierzeck at gmail.com>
> ---
>  arch/mips/Kconfig                     |  15 ++
>  arch/mips/Makefile                    |   1 +
>  arch/mips/mach-mt7620/Kconfig         | 130 ++++++++++
>  arch/mips/mach-mt7620/Makefile        |   8 +
>  arch/mips/mach-mt7620/cpu.c           |  66 +++++
>  arch/mips/mach-mt7620/ddr_calibrate.c | 331 +++++++++++++++++++++++++
>  arch/mips/mach-mt7620/lowlevel_init.S | 337 ++++++++++++++++++++++++++
>  arch/mips/mach-mt7620/mt76xx.h        |  39 +++
>  8 files changed, 927 insertions(+)
>  create mode 100644 arch/mips/mach-mt7620/Kconfig
>  create mode 100644 arch/mips/mach-mt7620/Makefile
>  create mode 100644 arch/mips/mach-mt7620/cpu.c
>  create mode 100644 arch/mips/mach-mt7620/ddr_calibrate.c
>  create mode 100644 arch/mips/mach-mt7620/lowlevel_init.S
>  create mode 100644 arch/mips/mach-mt7620/mt76xx.h
>
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 31b622ff51..af791c320d 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -87,6 +87,20 @@ config ARCH_BMIPS
>         select SYSRESET
>         imply CMD_DM
>
> +config ARCH_MT7620
> +       bool "Support MT7620/7688 SoCs"
> +       select SUPPORTS_LITTLE_ENDIAN
> +       select SUPPORTS_CPU_MIPS32_R1
> +       select SUPPORTS_CPU_MIPS32_R2
> +       select ROM_EXCEPTION_VECTORS
> +       select MIPS_TUNE_4KC

MT7620 has a MIPS 24kc core, thus you could optimize for that

> +       select OF_CONTROL
> +       select DM
> +       select DM_SERIAL
> +       select DM_SPI
> +       select DM_SPI_FLASH
> +       select DISPLAY_CPUINFO
> +

could you sort this in alphabetic order? There were some patches recently
which did the sorting tree wide. Also drop the SPI options until you add a
SPI driver.

>  config MACH_PIC32
>         bool "Support Microchip PIC32"
>         select DM
> @@ -141,6 +155,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
>
> diff --git a/arch/mips/Makefile b/arch/mips/Makefile
> index 5deec9a202..cc8ea5d7d4 100644
> --- a/arch/mips/Makefile
> +++ b/arch/mips/Makefile
> @@ -15,6 +15,7 @@ machine-$(CONFIG_SOC_AU1X00) += au1x00
>  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/mach-mt7620/Kconfig b/arch/mips/mach-mt7620/Kconfig
> new file mode 100644
> index 0000000000..40e15b8a31
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/Kconfig
> @@ -0,0 +1,130 @@
> +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"
> +
> +config BOARD_LINKIT_SMART_7688
> +       bool "LinkIt Smart 7688"
> +       depends on SOC_MT7620
> +       select SUPPORTS_BOOT_RAM
> +       help
> +         Seeed LinkIt Smart 7688 boards have a MT7688 SoC with 128 MiB of RAM
> +         and 32 MiB of flash (SPI).
> +         Between its different peripherals there's an integrated switch with 4
> +         ethernet ports, 1 USB port, 1 UART, GPIO buttons and LEDs, and
> +         a MT7688 (PCIe).

could you add this part with patch 3/4?

> +
> +endchoice
> +
> +choice
> +       prompt "Boot mode"
> +
> +config BOOT_RAM
> +       bool "RAM boot"
> +       depends on SUPPORTS_BOOT_RAM
> +       select SKIP_LOWLEVEL_INIT
> +       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
> +
> +config SKIP_LOWLEVEL_INIT
> +       bool

this is a legacy config option, thus you have to define it in your
board config header file.
MIPS shouldn't add a Kconfig symbol for that. This have to be migrated
to Kconfig tree-wide.

> +
> +source "board/seeed/linkit-smart-7688/Kconfig"

could you add this part with patch 3/4?

> +
> +endmenu
> diff --git a/arch/mips/mach-mt7620/Makefile b/arch/mips/mach-mt7620/Makefile
> new file mode 100644
> index 0000000000..1f3e65e8a5
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/Makefile
> @@ -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
> index 0000000000..0b22956499
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/cpu.c
> @@ -0,0 +1,66 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2018 Stefan Roese <sr at 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)
> +{
> +       void (*ptr)(void);
> +
> +       /*
> +        * DDR calibration routine needs to be called very early. This
> +        * function also configures the clock to run at full speed.
> +        */
> +       ptr = (void *)CKSEG0ADDR(ddr_calibrate);
> +       (*ptr)();

what is the purpose of forcing the function symbol to KSEG0?

> +
> +       return 0;
> +}
> +#endif
> +
> +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)" };
> +       char *chr = (char *)MT76XX_CHIPID;
> +       char buf[STR_LEN + 1];
> +       u32 val;
> +
> +       snprintf(buf, STR_LEN + 1, "%s", chr);
> +       val = readl((void *)MT76XX_CHIP_REV_ID);
> +       printf("CPU:   %-*s Rev %ld.%ld - ", STR_LEN, buf,
> +              (val & GENMASK(11, 8)) >> 8, val & GENMASK(3, 0));
> +
> +       val = (readl((void *)MT76XX_SYSCFG0) & GENMASK(3, 1)) >> 1;
> +       printf("Boot from %s\n", boot_str[val]);

could you try to create a CPU driver like on BMIPS?

> +
> +       return 0;
> +}
> +
> +void _machine_restart(void)
> +{
> +       writel(0x01, (void *)MT76XX_RSTCTL);
> +
> +       while (1)
> +               ;       /* NOP */

could you try to create a reset controller driver? Then you could also
use the generic syscon-reboot driver.

> +}
> +
> +int dram_init(void)
> +{
> +       gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, SZ_256M);

shouldn't you return the real configured DRAM size here?

> +
> +       return 0;
> +}
> diff --git a/arch/mips/mach-mt7620/ddr_calibrate.c b/arch/mips/mach-mt7620/ddr_calibrate.c
> new file mode 100644
> index 0000000000..6fd136674e
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/ddr_calibrate.c
> @@ -0,0 +1,331 @@
> +// 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 <linux/io.h>
> +#include <asm/cacheops.h>
> +#include <asm/io.h>
> +#include "mt76xx.h"
> +
> +#define NUM_OF_CACHELINE       64
> +#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)))
> +
> +#define cache_op(op, addr)                                             \
> +       __asm__ __volatile__(                                           \
> +               ".set   push\n"                                         \
> +               ".set   noreorder\n"                                    \
> +               ".set   mips3\n"                                        \
> +               "cache  %0, %1\n"                                       \
> +               ".set   pop\n"                                          \
> +               :                                                       \
> +               : "i" (op), "R" (*(u8 *)(addr)))

cache_op() is already available in arch/mips/include/asm/cacheops.h.
Maybe you could add pref_op in the same way to that file.

> +
> +static inline void cal_invalidate_dcache_range(u32 start_addr, u32 stop)
> +{
> +       u32 lsize = CONFIG_SYS_CACHELINE_SIZE;
> +       u32 addr = start_addr & ~(lsize - 1);
> +       u32 aend = (stop - 1) & ~(lsize - 1);
> +
> +       while (1) {
> +               cache_op(HIT_INVALIDATE_D, addr);
> +               if (addr == aend)
> +                       break;
> +               addr += lsize;
> +       }
> +}

you should use the generic MIPS implementation instead

> +
> +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, 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),
> +                              MT76XX_MEMCTRL_BASE + 0x64);
> +               else
> +                       writel(0x00007400 |
> +                              (((k == 1) ? coarse_dqs[dqs] : test_dqs) << 4) |
> +                              (((k == 0) ? val : test_dqs) << 0),
> +                              MT76XX_MEMCTRL_BASE + 0x64);
> +               wmb();          /* Make sure store if finished */
> +
> +               cal_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(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(MT76XX_DYN_CFG0_REG);
> +               fdiv = (val >> 8) & 0x0f;
> +               fdiv--;
> +               val &= ~(0x0f << 8);
> +               val |= (fdiv << 8);
> +               writel(val, MT76XX_DYN_CFG0_REG);
> +               udelay(500);
> +               val = readl(MT76XX_DYN_CFG0_REG);
> +               fdiv = (val >> 8) & 0x0f;
> +       }
> +
> +       clrbits_le32(MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
> +       ddr_cfg2_reg = readl(MT76XX_MEMCTRL_BASE + 0x48);
> +       clrbits_le32(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(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(MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
> +       writel(reg, MT76XX_MEMCTRL_BASE + 0x64);
> +       writel(ddr_cfg2_reg, MT76XX_MEMCTRL_BASE + 0x48);
> +       setbits_le32(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
> index 0000000000..92b2fcd2bb
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/lowlevel_init.S
> @@ -0,0 +1,337 @@
> +/* 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/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
> +
> +LEAF(lowlevel_init)
> +       /* 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)
> +       j       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  */
> +       li      t1, MT76XX_RGCTRL_BASE+0x100
> +       lw      t4, 0(t1)
> +       li      t2, BIT(31)
> +       or      t4, t4, t2
> +       sw      t4, 0(t1)
> +       li      t1, MT76XX_RGCTRL_BASE+0x10c
> +       lw      t4, 0(t1)
> +       j       LDO_1P8V
> +       nop
> +LDO_1P8V:
> +       li      t2, ~BIT(6)
> +       and     t4, t4, t2
> +       li      t1, MT76XX_RGCTRL_BASE+0x10c
> +       sw      t4, 0(t1)
> +       j       DDRLDO_SOFT_START
> +LDO_2P5V:
> +       /* suppose external DDR1 LDO 2.5V */
> +       li      t2, BIT(6)
> +       or      t4, t4, t2
> +       li      t1, MT76XX_RGCTRL_BASE+0x10c
> +       sw      t4, 0(t1)
> +
> +DDRLDO_SOFT_START:
> +       li      t1, MT76XX_RGCTRL_BASE+0x10c
> +       lw      t2, 0(t1)
> +       li      t3, BIT(16)
> +       or      t2, t2, t3
> +       sw      t2, 0(t1)
> +       li      t3, DELAY_USEC(250*50)
> +LDO_DELAY:
> +       subu    t3, t3, 1
> +       bnez    t3, LDO_DELAY
> +       nop
> +
> +       li      t1, MT76XX_RGCTRL_BASE+0x10c
> +       lw      t2, 0(t1)
> +       li      t3, BIT(18)
> +       or      t2, t2, t3
> +       sw      t2, 0(t1)
> +
> +SET_RG_BUCK_FPWM:
> +       li      t1, MT76XX_RGCTRL_BASE+0x104
> +       lw      t2, 0(t1)
> +       ori     t2, t2, BIT(10)
> +       sw      t2, 0(t1)
> +
> +DDR_PAD_CFG:
> +       /* clean CLK PAD */
> +       li      t1, MT76XX_RGCTRL_BASE+0x704
> +       lw      t2, 0(t1)
> +       li      t8, 0xfffff0f0
> +       and     t2, t2, t8
> +       /* clean CMD PAD */
> +       li      t1, MT76XX_RGCTRL_BASE+0x70c
> +       lw      t3, 0(t1)
> +       li      t8, 0xfffff0f0
> +       and     t3, t3, t8
> +       /* clean DQ IPAD */
> +       li      t1, MT76XX_RGCTRL_BASE+0x710
> +       lw      t4, 0(t1)
> +       li      t8, 0xfffff8ff
> +       and     t4, t4, t8
> +       /* clean DQ OPAD */
> +       li      t1, MT76XX_RGCTRL_BASE+0x714
> +       lw      t5, 0(t1)
> +       li      t8, 0xfffff0f0
> +       and     t5, t5, t8
> +       /* clean DQS IPAD */
> +       li      t1, MT76XX_RGCTRL_BASE+0x718
> +       lw      t6, 0(t1)
> +       li      t8, 0xfffff8ff
> +       and     t6, t6, t8
> +       /* clean DQS OPAD */
> +       li      t1, MT76XX_RGCTRL_BASE+0x71c
> +       lw      t7, 0(t1)
> +       li      t8, 0xfffff0f0
> +       and     t7, t7, t8
> +
> +       li      t1, MT76XX_SYSCTL_BASE+0xC
> +       lw      t9, 0(t1)
> +       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:
> +       li      t1, MT76XX_SYSCTL_BASE+0x10
> +       lw      t1, 0(t1)
> +       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:
> +       li      t1, MT76XX_RGCTRL_BASE+0x704
> +       sw      t2, 0(t1)
> +       li      t1, MT76XX_RGCTRL_BASE+0x70c
> +       sw      t3, 0(t1)
> +       li      t1, MT76XX_RGCTRL_BASE+0x710
> +       sw      t4, 0(t1)
> +       li      t1, MT76XX_RGCTRL_BASE+0x714
> +       sw      t5, 0(t1)
> +       li      t1, MT76XX_RGCTRL_BASE+0x718
> +       sw      t6, 0(t1)
> +       li      t1, MT76XX_RGCTRL_BASE+0x71c
> +       sw      t7, 0(t1)
> +
> +       /*
> +        * DDR initialization: reset pin to 0
> +        */
> +       li      t1, MT76XX_SYSCTL_BASE + 0x34
> +       lw      t2, 0(t1)
> +       and     t2, ~BIT(10)
> +       sw      t2, 0(t1)
> +       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)
> +        */
> +       li      t0, MT76XX_MEMCTRL_BASE + 0x14
> +       lw      t1, 0(t0)
> +       nop
> +       and     t1, 0xff000000
> +       or      t1, 0x01
> +       sw      t1, 0(t0)
> +       nop
> +       li      t0, MT76XX_MEMCTRL_BASE + 0x10
> +       lw      t1, 0(t0)
> +       nop
> +       or      t1, 0x10
> +       sw      t1, 0(t0)
> +       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
> index 0000000000..712d8aade0
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/mt76xx.h
> @@ -0,0 +1,39 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2018 Stefan Roese <sr at denx.de>
> + */
> +
> +#ifndef __MT76XX_H
> +#define __MT76XX_H
> +
> +#ifdef __ASSEMBLY__
> +#define VOID_PTR
> +#else
> +#define VOID_PTR               (void *)
> +#endif
> +
> +#define MT76XX_SYSCTL_BASE     0xb0000000
> +
> +#define MT76XX_CHIPID          (VOID_PTR(MT76XX_SYSCTL_BASE + 0x00))
> +#define MT76XX_CHIP_REV_ID     (VOID_PTR(MT76XX_SYSCTL_BASE + 0x0c))
> +#define MT76XX_SYSCFG0         (VOID_PTR(MT76XX_SYSCTL_BASE + 0x10))
> +#define MT76XX_RSTCTL          (VOID_PTR(MT76XX_SYSCTL_BASE + 0x34))
> +
> +#define MT76XX_MEMCTRL_BASE    (VOID_PTR(MT76XX_SYSCTL_BASE + 0x0300))
> +#define MT76XX_RGCTRL_BASE     (VOID_PTR(MT76XX_SYSCTL_BASE + 0x1000))
> +
> +#define MT76XX_ROM_STATUS_REG  (VOID_PTR(MT76XX_SYSCTL_BASE + 0x0028))
> +#define MT76XX_CLKCFG0_REG     (VOID_PTR(MT76XX_SYSCTL_BASE + 0x002c))
> +#define MT76XX_DYN_CFG0_REG    (VOID_PTR(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
> --
> 2.18.0
>



-- 
- Daniel


More information about the U-Boot mailing list