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 <s...@denx.de> > Cc: Daniel Schwierzeck <daniel.schwierz...@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@0 { > + compatible = "mti,mips24KEc"; > + device_type = "cpu"; > + reg = <0>; > + }; > + }; > + > + resetc: reset-controller { > + compatible = "ralink,rt2880-reset"; > + #reset-cells = <1>; > + }; > + > + cpuintc: interrupt-controller { > + #address-cells = <0>; > + #interrupt-cells = <1>; > + interrupt-controller; > + compatible = "mti,cpu-interrupt-controller"; > + }; > + > + palmbus@10000000 { > + compatible = "palmbus", "simple-bus"; > + reg = <0x10000000 0x200000>; > + ranges = <0x0 0x10000000 0x1FFFFF>; > + > + #address-cells = <1>; > + #size-cells = <1>; > + > + sysc: system-controller@0 { > + compatible = "ralink,mt7620a-sysc", "syscon"; > + reg = <0x0 0x100>; > + }; > + > + intc: interrupt-controller@200 { > + compatible = "ralink,rt2880-intc"; > + reg = <0x200 0x100>; > + > + interrupt-controller; > + #interrupt-cells = <1>; > + > + resets = <&resetc 9>; > + reset-names = "intc"; > + > + interrupt-parent = <&cpuintc>; > + interrupts = <2>; > + > + ralink,intc-registers = <0x9c 0xa0 > + 0x6c 0xa4 > + 0x80 0x78>; > + }; > + > + memory-controller@300 { > + compatible = "ralink,mt7620a-memc"; > + reg = <0x300 0x100>; > + }; > + > + spi0: spi@b00 { > + compatible = "ralink,mt7621-spi"; > + reg = <0xb00 0x40>; > + #address-cells = <1>; > + #size-cells = <0>; > + }; > + > + uart0: uartlite@c00 { > + compatible = "ns16550a"; > + reg = <0xc00 0x100>; > + > + resets = <&resetc 12>; > + reset-names = "uart0"; > + > + interrupt-parent = <&intc>; > + interrupts = <20>; > + > + reg-shift = <2>; > + }; > + > + uart1: uart1@d00 { > + compatible = "ns16550a"; > + reg = <0xd00 0x100>; > + > + resets = <&resetc 19>; > + reset-names = "uart1"; > + > + interrupt-parent = <&intc>; > + interrupts = <21>; > + > + reg-shift = <2>; > + }; > + > + uart2: uart2@e00 { > + compatible = "ns16550a"; > + reg = <0xe00 0x100>; > + > + resets = <&resetc 20>; > + reset-names = "uart2"; > + > + interrupt-parent = <&intc>; > + interrupts = <22>; > + > + reg-shift = <2>; > + }; > + }; > + > + usb_phy: usb-phy@10120000 { > + compatible = "mediatek,mt7628-usbphy"; > + reg = <0x10120000 0x1000>; > + > + #phy-cells = <0>; > + > + ralink,sysctl = <&sysc>; > + resets = <&resetc 22 &resetc 25>; > + reset-names = "host", "device"; > + }; > + > + ehci@101c0000 { > + compatible = "generic-ehci"; > + reg = <0x101c0000 0x1000>; > + > + phys = <&usb_phy>; > + phy-names = "usb"; > + > + interrupt-parent = <&intc>; > + interrupts = <18>; > + }; > +}; > diff --git a/arch/mips/mach-mt7620/Kconfig b/arch/mips/mach-mt7620/Kconfig > new file mode 100644 > 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 <s...@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 <s...@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 <s...@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 <s...@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
signature.asc
Description: OpenPGP digital signature
_______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot