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

Stefan sr at denx.de
Wed Sep 5 13:05:48 UTC 2018


Hi Daniel,

On 05.09.2018 13:45, Daniel Schwierzeck wrote:
> 
> 
> 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.

Ughh. This just slipped in from a debug version. I'll remove it
and will post this patch alone as v4 soon.

Thanks for spotting.
  
>> +#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 ;)

I missed this, thx.

> If you want to increase readabilty, you could add a define for this
> 0x100 offset.

Yes, that would be good. Unfortunately the documentation is not
very good and the original source code has no macros / defines
here as well. So its pretty hard to impossible for me to add such
defines.

Thanks,
Stefan


More information about the U-Boot mailing list