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

Daniel Schwierzeck daniel.schwierzeck at gmail.com
Wed Sep 5 11:45:34 UTC 2018



On 16.08.2018 15:27, Stefan Roese wrote:
> 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 at denx.de>
> Cc: Daniel Schwierzeck <daniel.schwierzeck at gmail.com>
> ---
> v3:
> - Added dtsi file with this platforms support as suggested by Daniel
> - Rebased on top of Daniels I-cache startup patches -> removed magic
>   with KSEG0 call of ddr_calibrate. Its now called directly and the
>   bootup is much faster
> - Some improvements to print_cpuinfo(), use ioremap_nocache etc
> - Added .set noreorder to lowlevel_init.S
> - Multiple improvements to lowlevel_init.S as suggested by Daniel
> 
> v2:
> - Sort Kconfig symbols alphabetically
> - Use MIPS_TUNE_24KC
> - Use imply for SPI support
> - Dont' add LinkIt module support yet (is added with the board support)
> - Move SKIP_LOWLEVEL_INIT from Kconfig to config header
> - Use DT to get the base address of the system controller (for
>   display_cpuinfo)
> - Remove _machine_restart - a separate driver is provided in a new patch
> - Remove cachop_op() and cal_invalidate_dcache_range and use the
>   generic invalidate_dcache_range function instead
> 
>  arch/mips/Kconfig                     |  16 +
>  arch/mips/Makefile                    |   1 +
>  arch/mips/dts/mt7628a.dtsi            | 135 +++++++++
>  arch/mips/mach-mt7620/Kconfig         | 113 +++++++
>  arch/mips/mach-mt7620/Makefile        |   8 +
>  arch/mips/mach-mt7620/cpu.c           |  69 +++++
>  arch/mips/mach-mt7620/ddr_calibrate.c | 308 +++++++++++++++++++
>  arch/mips/mach-mt7620/lowlevel_init.S | 406 ++++++++++++++++++++++++++
>  arch/mips/mach-mt7620/mt76xx.h        |  32 ++
>  9 files changed, 1088 insertions(+)
>  create mode 100644 arch/mips/dts/mt7628a.dtsi
>  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 6e5e0ffe65..b3981ef2e6 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -68,6 +68,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
> @@ -120,6 +135,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 a36f5f1fb6..802244a06e 100644
> --- a/arch/mips/Makefile
> +++ b/arch/mips/Makefile
> @@ -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
> index 0000000000..d00f528e1f
> --- /dev/null
> +++ b/arch/mips/dts/mt7628a.dtsi
> @@ -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 at 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 at 10000000 {
> +		compatible = "palmbus", "simple-bus";
> +		reg = <0x10000000 0x200000>;
> +		ranges = <0x0 0x10000000 0x1FFFFF>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +
> +		sysc: system-controller at 0 {
> +			compatible = "ralink,mt7620a-sysc", "syscon";
> +			reg = <0x0 0x100>;
> +		};
> +
> +		intc: interrupt-controller at 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 at 300 {
> +			compatible = "ralink,mt7620a-memc";
> +			reg = <0x300 0x100>;
> +		};
> +
> +		spi0: spi at b00 {
> +			compatible = "ralink,mt7621-spi";
> +			reg = <0xb00 0x40>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +
> +		uart0: uartlite at c00 {
> +			compatible = "ns16550a";
> +			reg = <0xc00 0x100>;
> +
> +			resets = <&resetc 12>;
> +			reset-names = "uart0";
> +
> +			interrupt-parent = <&intc>;
> +			interrupts = <20>;
> +
> +			reg-shift = <2>;
> +		};
> +
> +		uart1: uart1 at d00 {
> +			compatible = "ns16550a";
> +			reg = <0xd00 0x100>;
> +
> +			resets = <&resetc 19>;
> +			reset-names = "uart1";
> +
> +			interrupt-parent = <&intc>;
> +			interrupts = <21>;
> +
> +			reg-shift = <2>;
> +		};
> +
> +		uart2: uart2 at e00 {
> +			compatible = "ns16550a";
> +			reg = <0xe00 0x100>;
> +
> +			resets = <&resetc 20>;
> +			reset-names = "uart2";
> +
> +			interrupt-parent = <&intc>;
> +			interrupts = <22>;
> +
> +			reg-shift = <2>;
> +		};
> +	};
> +
> +	usb_phy: usb-phy at 10120000 {
> +		compatible = "mediatek,mt7628-usbphy";
> +		reg = <0x10120000 0x1000>;
> +
> +		#phy-cells = <0>;
> +
> +		ralink,sysctl = <&sysc>;
> +		resets = <&resetc 22 &resetc 25>;
> +		reset-names = "host", "device";
> +	};
> +
> +	ehci at 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
> index 0000000000..396fbd0141
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/Kconfig
> @@ -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
> 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..457f09f32c
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/cpu.c
> @@ -0,0 +1,69 @@
> +// 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)
> +{
> +	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
> index 0000000000..e178d14c76
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/ddr_calibrate.c
> @@ -0,0 +1,308 @@
> +// 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)))
> +
> +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
> index 0000000000..740d132f98
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/lowlevel_init.S
> @@ -0,0 +1,406 @@
> +/* 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

maybe this register address could be loaded too into a sN register
because it's used multiple times.

> +	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:
> +#if 0

do you need this code in the future? Otherwise it should be removed to
avoid adding dead code.

> +#define RALINK_SYSCTL_BASE		0xB0000000
> +	// GPIO mode
> +	li	t0, RALINK_SYSCTL_BASE + 0x64
> +	li	t1, 0x05540551
> +	sw	t1, 0(t0)
> +
> +	// GPIO direction
> +	li	t0, RALINK_SYSCTL_BASE + 0x604
> +	li	t1, 0x00001000
> +	sw	t1, 0(t0)
> +
> +	// GPIO value
> +	li	t0, RALINK_SYSCTL_BASE + 0x624
> +	li	t1, 0x0002f5f
> +	sw	t1, 0(t0)
> +
> +	li	t0, DELAY_USEC(1000000)
> +	li	t1, 0x1
> +1:
> +	sub	t0, t0, t1
> +	bnez	t0, 1b
> +	nop
> +
> +	// GPIO value
> +	li	t0, RALINK_SYSCTL_BASE + 0x624
> +	li	t1, 0x0003f5f
> +	sw	t1, 0(t0)
> +
> +	li	t0, DELAY_USEC(1000000)
> +	li	t1, 0x1
> +1:
> +	sub	t0, t0, t1
> +	bnez	t0, 1b
> +	nop
> +
> +	// GPIO value
> +	li	t0, RALINK_SYSCTL_BASE + 0x624
> +	li	t1, 0x0002f5f
> +	sw	t1, 0(t0)
> +
> +	li	t0, DELAY_USEC(1000000)
> +	li	t1, 0x1
> +1:
> +	sub	t0, t0, t1
> +	bnez	t0, 1b
> +	nop
> +
> +	// GPIO value
> +	li	t0, RALINK_SYSCTL_BASE + 0x624
> +	li	t1, 0x0003f5f
> +	sw	t1, 0(t0)
> +
> +	li	t0, DELAY_USEC(1000000)
> +	li	t1, 0x1
> +1:
> +	sub	t0, t0, t1
> +	bnez	t0, 1b
> +	nop
> +
> +	// GPIO value
> +	li	t0, RALINK_SYSCTL_BASE + 0x624
> +	li	t1, 0x0002f5f
> +	sw	t1, 0(t0)
> +
> +#endif
> +	/*
> +	 * 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  */
> +	la	t1, 0x100(s2)
> +	lw	t4, 0(t1)

this could be simply written as

        lw      t4, 0x100(s2)

this was the main intention of my suggested optimisation ;)
If you want to increase readabilty, you could add a define for this
0x100 offset.

> +	li	t2, BIT(31)
> +	or	t4, t4, t2
> +	sw	t4, 0(t1)
> +	la	t1, 0x10c(s2)
> +	lw	t4, 0(t1)
> +	j	LDO_1P8V
> +	nop
> +LDO_1P8V:
> +	li	t2, ~BIT(6)
> +	and	t4, t4, t2
> +	la	t1, 0x10c(s2)
> +	sw	t4, 0(t1)
> +	j	DDRLDO_SOFT_START
> +LDO_2P5V:
> +	/* suppose external DDR1 LDO 2.5V */
> +	li	t2, BIT(6)
> +	or	t4, t4, t2
> +	la	t1, 0x10c(s2)
> +	sw	t4, 0(t1)
> +
> +DDRLDO_SOFT_START:
> +	la	t1, 0x10c(s2)
> +	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
> +
> +	la	t1, 0x10c(s2)
> +	lw	t2, 0(t1)
> +	li	t3, BIT(18)
> +	or	t2, t2, t3
> +	sw	t2, 0(t1)
> +
> +SET_RG_BUCK_FPWM:
> +	la	t1, 0x104(s2)
> +	lw	t2, 0(t1)
> +	ori	t2, t2, BIT(10)
> +	sw	t2, 0(t1)
> +
> +DDR_PAD_CFG:
> +	/* clean CLK PAD */
> +	la	t1, 0x704(s2)
> +	lw	t2, 0(t1)
> +	li	t8, 0xfffff0f0
> +	and	t2, t2, t8
> +	/* clean CMD PAD */
> +	la	t1, 0x70c(s2)
> +	lw	t3, 0(t1)
> +	li	t8, 0xfffff0f0
> +	and	t3, t3, t8
> +	/* clean DQ IPAD */
> +	la	t1, 0x710(s2)
> +	lw	t4, 0(t1)
> +	li	t8, 0xfffff8ff
> +	and	t4, t4, t8
> +	/* clean DQ OPAD */
> +	la	t1, 0x714(s2)
> +	lw	t5, 0(t1)
> +	li	t8, 0xfffff0f0
> +	and	t5, t5, t8
> +	/* clean DQS IPAD */
> +	la	t1, 0x718(s2)
> +	lw	t6, 0(t1)
> +	li	t8, 0xfffff8ff
> +	and	t6, t6, t8
> +	/* clean DQS OPAD */
> +	la	t1, 0x71c(s2)
> +	lw	t7, 0(t1)
> +	li	t8, 0xfffff0f0
> +	and	t7, t7, t8
> +
> +	la	t1, 0xc(s0)
> +	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:
> +	la	t1, 0x10(s0)
> +	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:
> +	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
> +	 */
> +	la	t1, 0x34(s0)
> +	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)
> +	 */
> +	la	t0, 0x14(s1)
> +	lw	t1, 0(t0)
> +	nop
> +	and	t1, 0xff000000
> +	or	t1, 0x01
> +	sw	t1, 0(t0)
> +	nop
> +	la	t0, 0x10(s1)
> +	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..17473ea8f1
> --- /dev/null
> +++ b/arch/mips/mach-mt7620/mt76xx.h
> @@ -0,0 +1,32 @@
> +/* 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
> 

-- 
- Daniel

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20180905/c8ce0792/attachment.sig>


More information about the U-Boot mailing list