From mboxrd@z Thu Jan 1 00:00:00 1970 From: Stefan Date: Wed, 5 Sep 2018 15:05:48 +0200 Subject: [U-Boot] [PATCH 1/6 v3] mips: Add basic MediaTek MT7620/88 support In-Reply-To: <109c9491-998a-5eca-f6ee-63712123944d@gmail.com> References: <20180816132733.19408-1-sr@denx.de> <109c9491-998a-5eca-f6ee-63712123944d@gmail.com> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 >> Cc: Daniel Schwierzeck >> --- >> 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 >> + */ >> + >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#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 >> + * >> + * 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 >> +#include >> +#include >> +#include >> +#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 >> + * >> + * 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 >> +#include >> +#include >> +#include >> +#include >> +#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