diff options
author | Weijie Gao | 2022-05-20 11:22:21 +0800 |
---|---|---|
committer | Daniel Schwierzeck | 2022-07-13 23:03:37 +0200 |
commit | 4bc0104c976b910c49547f6f38f806e1b13f047d (patch) | |
tree | c6d52b05d8358b1b8cf7d75cbcaff281843370ec /arch/mips | |
parent | 2948d9cf8637e49e2a172b8936a9f5a3a04bca13 (diff) |
mips: mtmips: add support for MediaTek MT7621 SoC
This patch adds support for MediaTek MT7621 SoC.
All files are dedicated for u-boot.
The default build target is u-boot-mt7621.bin.
The specification of this chip:
https://www.mediatek.com/products/homenetworking/mt7621
Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
Diffstat (limited to 'arch/mips')
25 files changed, 2643 insertions, 6 deletions
diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 32c436f2bcb..a007914590f 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -4,6 +4,11 @@ head-y := arch/mips/cpu/start.o ifeq ($(CONFIG_SPL_BUILD),y) head-$(CONFIG_ARCH_JZ47XX) := arch/mips/mach-jz47xx/start.o +head-$(CONFIG_SOC_MT7621) := arch/mips/mach-mtmips/mt7621/spl/start.o +endif + +ifeq ($(CONFIG_TPL_BUILD),y) +head-$(CONFIG_SOC_MT7621) := arch/mips/mach-mtmips/mt7621/tpl/start.o endif libs-y += arch/mips/cpu/ diff --git a/arch/mips/dts/mt7621-u-boot.dtsi b/arch/mips/dts/mt7621-u-boot.dtsi new file mode 100644 index 00000000000..c5a8aa357f9 --- /dev/null +++ b/arch/mips/dts/mt7621-u-boot.dtsi @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <linux/stringify.h> + +/ { + binman: binman { + multiple-images; + }; +}; + +&sysc { + u-boot,dm-pre-reloc; +}; + +&reboot { + u-boot,dm-pre-reloc; +}; + +&clkctrl { + u-boot,dm-pre-reloc; +}; + +&rstctrl { + u-boot,dm-pre-reloc; +}; + +&pinctrl { + u-boot,dm-pre-reloc; +}; + +&uart0 { + u-boot,dm-pre-reloc; +}; + +&uart1 { + u-boot,dm-pre-reloc; +}; + +&uart2 { + u-boot,dm-pre-reloc; +}; + +&binman { + u-boot-spl-ddr { + align = <4>; + align-size = <4>; + filename = "u-boot-spl-ddr.bin"; + pad-byte = <0xff>; + + u-boot-spl { + align-end = <4>; + filename = "u-boot-spl.bin"; + }; + + stage_bin { + filename = "mt7621_stage_sram.bin"; + type = "blob-ext"; + }; + }; + + spl-img { + filename = "u-boot-spl-ddr.img"; + + mkimage { +#ifdef CONFIG_MT7621_BOOT_FROM_NAND + args = "-T", "mtk_image", "-n", "mt7621=1", + "-a", __stringify(CONFIG_SPL_TEXT_BASE), + "-e", __stringify(CONFIG_SPL_TEXT_BASE); +#else + args = "-A", "mips", "-T", "standalone", "-O", "u-boot", + "-C", "none", "-n", "MT7621 U-Boot SPL", + "-a", __stringify(CONFIG_SPL_TEXT_BASE), + "-e", __stringify(CONFIG_SPL_TEXT_BASE); +#endif + + blob { + filename = "u-boot-spl-ddr.bin"; + }; + }; + }; + + mt7621-uboot { + filename = "u-boot-mt7621.bin"; + pad-byte = <0xff>; + +#ifndef CONFIG_MT7621_BOOT_FROM_NAND + u-boot-tpl { + align-end = <4>; + filename = "u-boot-tpl.bin"; + }; +#endif + + spl { +#ifdef CONFIG_MT7621_BOOT_FROM_NAND + align-end = <0x1000>; +#endif + filename = "u-boot-spl-ddr.img"; + type = "blob"; + }; + + u-boot { + filename = "u-boot-lzma.img"; + type = "blob"; + }; + }; +}; diff --git a/arch/mips/dts/mt7621.dtsi b/arch/mips/dts/mt7621.dtsi new file mode 100644 index 00000000000..c32b6095e99 --- /dev/null +++ b/arch/mips/dts/mt7621.dtsi @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <dt-bindings/clock/mt7621-clk.h> +#include <dt-bindings/reset/mt7621-reset.h> +#include <dt-bindings/phy/phy.h> + +/ { + #address-cells = <1>; + #size-cells = <1>; + compatible = "mediatek,mt7621-soc"; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "mips,mips1004Kc"; + reg = <0>; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "mips,mips1004Kc"; + reg = <1>; + }; + }; + + clk48m: clk48m { + compatible = "fixed-clock"; + + clock-frequency = <48000000>; + + #clock-cells = <0>; + }; + + clk50m: clk50m { + compatible = "fixed-clock"; + + clock-frequency = <50000000>; + + #clock-cells = <0>; + }; + + sysc: sysctrl@1e000000 { + compatible = "mediatek,mt7621-sysc", "syscon"; + reg = <0x1e000000 0x100>; + + clkctrl: clock-controller@1e000030 { + compatible = "mediatek,mt7621-clk"; + mediatek,memc = <&memc>; + + #clock-cells = <1>; + }; + }; + + rstctrl: reset-controller@1e000034 { + compatible = "mediatek,mtmips-reset"; + reg = <0x1e000034 0x4>; + #reset-cells = <1>; + }; + + reboot: resetctl-reboot { + compatible = "resetctl-reboot"; + + resets = <&rstctrl RST_SYS>; + reset-names = "sysreset"; + }; + + memc: memctrl@1e005000 { + compatible = "mediatek,mt7621-memc", "syscon"; + reg = <0x1e005000 0x1000>; + }; + + pinctrl: pinctrl@1e000060 { + compatible = "mediatek,mt7621-pinctrl"; + reg = <0x1e000048 0x30>; + + pinctrl-names = "default"; + pinctrl-0 = <&state_default>; + + state_default: pin_state { + }; + + uart1_pins: uart1_pins { + groups = "uart1"; + function = "uart"; + }; + + uart2_pins: uart2_pins { + groups = "uart2"; + function = "uart"; + }; + + uart3_pins: uart3_pins { + groups = "uart3"; + function = "uart"; + }; + + sdxc_pins: sdxc_pins { + groups = "sdxc"; + function = "sdxc"; + }; + + spi_pins: spi_pins { + groups = "spi"; + function = "spi"; + }; + + eth_pins: eth_pins { + mdio_pins { + groups = "mdio"; + function = "mdio"; + }; + + rgmii1_pins { + groups = "rgmii1"; + function = "rgmii"; + }; + + esw_pins { + groups = "esw int"; + function = "esw int"; + }; + + mdio_pconf { + groups = "mdio"; + drive-strength = <2>; + }; + }; + }; + + watchdog: watchdog@1e000100 { + compatible = "mediatek,mt7621-wdt"; + reg = <0x1e000100 0x40>; + + resets = <&rstctrl RST_TIMER>; + reset-names = "wdt"; + + status = "disabled"; + }; + + gpio: gpio@1e000600 { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "mtk,mt7621-gpio"; + reg = <0x1e000600 0x100>; + + resets = <&rstctrl RST_PIO>; + reset-names = "pio"; + + gpio0: bank@0 { + reg = <0>; + compatible = "mtk,mt7621-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio1: bank@1 { + reg = <1>; + compatible = "mtk,mt7621-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio2: bank@2 { + reg = <2>; + compatible = "mtk,mt7621-gpio-bank"; + gpio-controller; + #gpio-cells = <2>; + }; + }; + + spi: spi@1e000b00 { + compatible = "ralink,mt7621-spi"; + reg = <0x1e000b00 0x40>; + + status = "disabled"; + + pinctrl-names = "default"; + pinctrl-0 = <&spi_pins>; + + resets = <&rstctrl RST_SPI>; + reset-names = "spi"; + + clocks = <&clkctrl MT7621_CLK_SPI>; + + #address-cells = <1>; + #size-cells = <0>; + }; + + uart0: uart1@1e000c00 { + compatible = "mediatek,hsuart", "ns16550a"; + reg = <0x1e000c00 0x100>; + + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>; + + clocks = <&clkctrl MT7621_CLK_UART1>; + + resets = <&rstctrl RST_UART1>; + + reg-shift = <2>; + }; + + uart1: uart2@1e000d00 { + compatible = "mediatek,hsuart", "ns16550a"; + reg = <0x1e000d00 0x100>; + + pinctrl-names = "default"; + pinctrl-0 = <&uart2_pins>; + + clocks = <&clkctrl MT7621_CLK_UART2>; + + resets = <&rstctrl RST_UART2>; + + reg-shift = <2>; + + status = "disabled"; + }; + + uart2: uart3@1e000e00 { + compatible = "mediatek,hsuart", "ns16550a"; + reg = <0x1e000e00 0x100>; + + pinctrl-names = "default"; + pinctrl-0 = <&uart3_pins>; + + clocks = <&clkctrl MT7621_CLK_UART3>; + + resets = <&rstctrl RST_UART3>; + + reg-shift = <2>; + + status = "disabled"; + }; + + eth: eth@1e100000 { + compatible = "mediatek,mt7621-eth"; + reg = <0x1e100000 0x20000>; + mediatek,ethsys = <&sysc>; + + pinctrl-names = "default"; + pinctrl-0 = <ð_pins>; + + resets = <&rstctrl RST_FE>, <&rstctrl RST_GMAC>, <&rstctrl RST_MCM>; + reset-names = "fe", "gmac", "mcm"; + + clocks = <&clkctrl MT7621_CLK_GDMA>, + <&clkctrl MT7621_CLK_ETH>; + clock-names = "gmac", "fe"; + + #address-cells = <1>; + #size-cells = <0>; + + mediatek,gmac-id = <0>; + phy-mode = "rgmii"; + mediatek,switch = "mt7530"; + mediatek,mcm; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + + mmc: mmc@1e130000 { + compatible = "mediatek,mt7621-mmc"; + reg = <0x1e130000 0x4000>; + + status = "disabled"; + + bus-width = <4>; + builtin-cd = <1>; + r_smpl = <1>; + + pinctrl-names = "default"; + pinctrl-0 = <&sdxc_pins>; + + clocks = <&clk50m>, <&clkctrl MT7621_CLK_SHXC>; + clock-names = "source", "hclk"; + + resets = <&rstctrl RST_SDXC>; + }; + + ssusb: usb@1e1c0000 { + compatible = "mediatek,mt7621-xhci", "mediatek,mtk-xhci"; + reg = <0x1e1c0000 0x1000>, <0x1e1d0700 0x100>; + reg-names = "mac", "ippc"; + + clocks = <&clk48m>, <&clk48m>; + clock-names = "sys_ck", "ref_ck"; + + phys = <&u2port0 PHY_TYPE_USB2>, + <&u3port0 PHY_TYPE_USB3>, + <&u2port1 PHY_TYPE_USB2>; + + status = "disabled"; + }; + + u3phy: usb-phy@1e1d0000 { + compatible = "mediatek,mt7621-u3phy", + "mediatek,generic-tphy-v1"; + reg = <0x1e1d0000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + status = "disabled"; + + u2port0: usb-phy@1e1d0800 { + reg = <0x1e1d0800 0x0100>; + #phy-cells = <1>; + clocks = <&clk48m>; + clock-names = "ref"; + }; + + u3port0: usb-phy@1e1d0900 { + reg = <0x1e1d0900 0x0100>; + #phy-cells = <1>; + }; + + u2port1: usb-phy@1e1d1000 { + reg = <0x1e1d1000 0x0100>; + #phy-cells = <1>; + clocks = <&clk48m>; + clock-names = "ref"; + }; + }; + + i2c: i2c@1e000900 { + compatible = "i2c-gpio"; + + status = "disabled"; + + i2c-gpio,delay-us = <3>; + + gpios = <&gpio0 3 1>, /* PIN3 as SDA */ + <&gpio0 4 1>; /* PIN4 as CLK */ + + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/mips/mach-mtmips/Kconfig b/arch/mips/mach-mtmips/Kconfig index 151b004603d..d46be503a2b 100644 --- a/arch/mips/mach-mtmips/Kconfig +++ b/arch/mips/mach-mtmips/Kconfig @@ -9,6 +9,7 @@ config SYS_MALLOC_F_LEN config SYS_SOC default "mt7620" if SOC_MT7620 + default "mt7621" if SOC_MT7621 default "mt7628" if SOC_MT7628 config SYS_DCACHE_SIZE @@ -18,25 +19,45 @@ config SYS_DCACHE_LINE_SIZE default 32 config SYS_ICACHE_SIZE - default 65536 + default 65536 if SOC_MT7620 || SOC_MT7628 + default 32768 if SOC_MT7621 config SYS_ICACHE_LINE_SIZE default 32 +config SYS_SCACHE_LINE_SIZE + default 32 if SOC_MT7621 + config SYS_TEXT_BASE - default 0x9c000000 if !SPL - default 0x80200000 if SPL + default 0x9c000000 if !SPL && !SOC_MT7621 + default 0x80200000 if SPL || SOC_MT7621 config SPL_TEXT_BASE - default 0x9c000000 + default 0x9c000000 if !SOC_MT7621 + default 0x80100000 if SOC_MT7621 + +config SPL_SIZE_LIMIT + default 0x30000 if SOC_MT7621 + +config TPL_TEXT_BASE + default 0xbfc00000 if SOC_MT7621 + +config TPL_MAX_SIZE + default 4096 if SOC_MT7621 config SPL_PAYLOAD default "u-boot-lzma.img" if SPL_LZMA config BUILD_TARGET - default "u-boot-with-spl.bin" if SPL + default "u-boot-with-spl.bin" if SPL && !SOC_MT7621 + default "u-boot-lzma.img" if SOC_MT7621 default "u-boot.bin" +config MAX_MEM_SIZE + int + default 256 if SOC_MT7620 || SOC_MT7628 + default 512 if SOC_MT7621 + choice prompt "MediaTek MIPS SoC select" @@ -55,6 +76,23 @@ config SOC_MT7620 help This supports MediaTek MT7620. +config SOC_MT7621 + bool "MT7621" + select MIPS_CM + select MIPS_L2_CACHE + select SYS_CACHE_SHIFT_5 + select SYS_MIPS_CACHE_INIT_RAM_LOAD + select PINCTRL_MT7621 + select MTK_SERIAL + select REGMAP + select SYSCON + select BINMAN + select SUPPORT_TPL + select SPL_LOADER_SUPPORT if SPL + select SPL_INIT_STACK_WITHOUT_MALLOC_F if SPL + help + This supports MediaTek MT7621. + config SOC_MT7628 bool "MT7628" select SYS_CACHE_SHIFT_5 @@ -80,6 +118,7 @@ config SOC_MT7628 endchoice source "arch/mips/mach-mtmips/mt7620/Kconfig" +source "arch/mips/mach-mtmips/mt7621/Kconfig" source "arch/mips/mach-mtmips/mt7628/Kconfig" endmenu diff --git a/arch/mips/mach-mtmips/Makefile b/arch/mips/mach-mtmips/Makefile index 4909b47ef27..19f1e07033e 100644 --- a/arch/mips/mach-mtmips/Makefile +++ b/arch/mips/mach-mtmips/Makefile @@ -1,9 +1,13 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += cpu.o + +ifneq ($(CONFIG_SOC_MT7621),y) obj-y += ddr_init.o obj-y += ddr_cal.o obj-$(CONFIG_SPL_BUILD) += spl.o +endif obj-$(CONFIG_SOC_MT7620) += mt7620/ +obj-$(CONFIG_SOC_MT7621) += mt7621/ obj-$(CONFIG_SOC_MT7628) += mt7628/ diff --git a/arch/mips/mach-mtmips/cpu.c b/arch/mips/mach-mtmips/cpu.c index a4b5cff61d9..f1e90227386 100644 --- a/arch/mips/mach-mtmips/cpu.c +++ b/arch/mips/mach-mtmips/cpu.c @@ -16,7 +16,7 @@ DECLARE_GLOBAL_DATA_PTR; int dram_init(void) { - gd->ram_size = get_ram_size((void *)KSEG1, SZ_256M); + gd->ram_size = get_ram_size((void *)KSEG1, CONFIG_MAX_MEM_SIZE << 20); return 0; } diff --git a/arch/mips/mach-mtmips/mt7621/Kconfig b/arch/mips/mach-mtmips/mt7621/Kconfig new file mode 100644 index 00000000000..37d512c68fa --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/Kconfig @@ -0,0 +1,95 @@ + +if SOC_MT7621 + +menu "CPU & DDR configuration" + +config MT7621_CPU_FREQ + int "CPU Frequency (MHz)" + range 400 1200 + default 880 + +choice + prompt "DRAM Frequency" + default MT7621_DRAM_FREQ_1200 + +config MT7621_DRAM_FREQ_400 + bool "400MHz" + +config MT7621_DRAM_FREQ_800 + bool "800MHz" + +config MT7621_DRAM_FREQ_1066 + bool "1066MHz" + +config MT7621_DRAM_FREQ_1200 + bool "1200MHz" + +endchoice + +choice + prompt "DDR2 timing parameters" + default MT7621_DRAM_DDR2_1024M + +config MT7621_DRAM_DDR2_512M + bool "64MB" + +config MT7621_DRAM_DDR2_1024M + bool "128MB" + +config MT7621_DRAM_DDR2_512M_W9751G6KB_A02_1066MHZ + bool "W9751G6KB_A02 @ 1066MHz (64MB)" + +config MT7621_DRAM_DDR2_1024M_W971GG6KB25_800MHZ + bool "W971GG6KB25 @ 800MHz (128MB)" + +config MT7621_DRAM_DDR2_1024M_W971GG6KB18_1066MHZ + bool "W971GG6KB18 @ 1066MHz (128MB)" + +endchoice + +choice + prompt "DDR3 timing parameters" + default MT7621_DRAM_DDR3_2048M + +config MT7621_DRAM_DDR3_1024M + bool "128MB" + +config MT7621_DRAM_DDR3_1024M_KGD + bool "128MB KGD (MT7621DA)" + +config MT7621_DRAM_DDR3_2048M + bool "256MB" + +config MT7621_DRAM_DDR3_4096M + bool "512MB" + +endchoice + +endmenu + +config DEBUG_UART_BOARD_INIT + default y + +config MT7621_BOOT_FROM_NAND + bool "Boot from NAND" + help + Select this if u-boot will boot from NAND flash. When booting from + NAND, SPL will be loaded by bootrom directly and no TPL is needed. + +choice + prompt "Board select" + +endchoice + +config SYS_CONFIG_NAME + string "Board configuration name" + default "mt7621" if BOARD_MT7621_RFB || BOARD_MT7621_NAND_RFB + +config SYS_BOARD + string "Board name" + default "mt7621" if BOARD_MT7621_RFB || BOARD_MT7621_NAND_RFB + +config SYS_VENDOR + default "mediatek" if BOARD_MT7621_RFB || BOARD_MT7621_NAND_RFB + +endif diff --git a/arch/mips/mach-mtmips/mt7621/Makefile b/arch/mips/mach-mtmips/mt7621/Makefile new file mode 100644 index 00000000000..bf1b0bb688b --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/Makefile @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += init.o +obj-y += serial.o + +ifeq ($(CONFIG_SPL_BUILD),y) +ifeq ($(CONFIG_TPL_BUILD),y) +obj-y += tpl/ +else +obj-y += spl/ +endif + +obj-y += sram_init.o +endif diff --git a/arch/mips/mach-mtmips/mt7621/init.c b/arch/mips/mach-mtmips/mt7621/init.c new file mode 100644 index 00000000000..d21848ad23b --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/init.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <clk.h> +#include <dm.h> +#include <dm/uclass.h> +#include <dt-bindings/clock/mt7621-clk.h> +#include <asm/global_data.h> +#include <linux/io.h> +#include <linux/bitfield.h> +#include "mt7621.h" + +DECLARE_GLOBAL_DATA_PTR; + +static const char *const boot_mode[(CHIP_MODE_M >> CHIP_MODE_S) + 1] = { + [1] = "NAND 2K+64", + [2] = "SPI-NOR 3-Byte Addr", + [3] = "SPI-NOR 4-Byte Addr", + [10] = "NAND 2K+128", + [11] = "NAND 4K+128", + [12] = "NAND 4K+256", +}; + +int print_cpuinfo(void) +{ + void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE); + u32 val, ver, eco, pkg, core, dram, chipmode; + u32 cpu_clk, ddr_clk, bus_clk, xtal_clk; + struct udevice *clkdev; + const char *bootdev; + struct clk clk; + int ret; + + val = readl(sysc + SYSCTL_CHIP_REV_ID_REG); + ver = FIELD_GET(VER_ID_M, val); + eco = FIELD_GET(ECO_ID_M, val); + pkg = FIELD_GET(PKG_ID, val); + core = FIELD_GET(CPU_ID, val); + + val = readl(sysc + SYSCTL_SYSCFG0_REG); + dram = FIELD_GET(DRAM_TYPE, val); + chipmode = FIELD_GET(CHIP_MODE_M, val); + + bootdev = boot_mode[chipmode]; + if (!bootdev) + bootdev = "Unsupported boot mode"; + + printf("CPU: MediaTek MT7621%c ver %u, eco %u\n", + core ? (pkg ? 'A' : 'N') : 'S', ver, eco); + + printf("Boot: DDR%u, %s\n", dram ? 2 : 3, bootdev); + + ret = uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(mt7621_clk), + &clkdev); + if (ret) + return ret; + + clk.dev = clkdev; + + clk.id = MT7621_CLK_CPU; + cpu_clk = clk_get_rate(&clk); + + clk.id = MT7621_CLK_BUS; + bus_clk = clk_get_rate(&clk); + + clk.id = MT7621_CLK_DDR; + ddr_clk = clk_get_rate(&clk); + + clk.id = MT7621_CLK_XTAL; + xtal_clk = clk_get_rate(&clk); + + /* Set final timer frequency */ + if (cpu_clk) + gd->arch.timer_freq = cpu_clk / 2; + + printf("Clock: CPU: %uMHz, DDR: %uMT/s, Bus: %uMHz, XTAL: %uMHz\n", + cpu_clk / 1000000, ddr_clk / 500000, bus_clk / 1000000, + xtal_clk / 1000000); + + return 0; +} + +unsigned long get_xtal_mhz(void) +{ + void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE); + u32 bs, xtal_sel; + + bs = readl(sysc + SYSCTL_SYSCFG0_REG); + xtal_sel = FIELD_GET(XTAL_MODE_SEL_M, bs); + + if (xtal_sel <= 2) + return 20; + else if (xtal_sel <= 5) + return 40; + else + return 25; +} + +static void xhci_config_40mhz(void __iomem *usbh) +{ + writel(FIELD_PREP(SSUSB_MAC3_SYS_CK_GATE_MASK_TIME_M, 0x20) | + FIELD_PREP(SSUSB_MAC2_SYS_CK_GATE_MASK_TIME_M, 0x20) | + FIELD_PREP(SSUSB_MAC3_SYS_CK_GATE_MODE_M, 2) | + FIELD_PREP(SSUSB_MAC2_SYS_CK_GATE_MODE_M, 2) | 0x10, + usbh + SSUSB_MAC_CK_CTRL_REG); + + writel(FIELD_PREP(SSUSB_PLL_PREDIV_PE1D_M, 2) | + FIELD_PREP(SSUSB_PLL_PREDIV_U3_M, 1) | + FIELD_PREP(SSUSB_PLL_FBKDI_M, 4), + usbh + DA_SSUSB_U3PHYA_10_REG); + + writel(FIELD_PREP(SSUSB_PLL_FBKDIV_PE2H_M, 0x18) | + FIELD_PREP(SSUSB_PLL_FBKDIV_PE1D_M, 0x18) | + FIELD_PREP(SSUSB_PLL_FBKDIV_PE1H_M, 0x18) | + FIELD_PREP(SSUSB_PLL_FBKDIV_U3_M, 0x1e), + usbh + DA_SSUSB_PLL_FBKDIV_REG); + + writel(FIELD_PREP(SSUSB_PLL_PCW_NCPO_U3_M, 0x1e400000), + usbh + DA_SSUSB_PLL_PCW_NCPO_REG); + + writel(FIELD_PREP(SSUSB_PLL_SSC_DELTA1_PE1H_M, 0x25) | + FIELD_PREP(SSUSB_PLL_SSC_DELTA1_U3_M, 0x73), + usbh + DA_SSUSB_PLL_SSC_DELTA1_REG); + + writel(FIELD_PREP(SSUSB_PLL_SSC_DELTA_U3_M, 0x71) | + FIELD_PREP(SSUSB_PLL_SSC_DELTA1_PE2D_M, 0x4a), + usbh + DA_SSUSB_U3PHYA_21_REG); + + writel(FIELD_PREP(SSUSB_PLL_SSC_PRD_M, 0x140), + usbh + SSUSB_U3PHYA_9_REG); + + writel(FIELD_PREP(SSUSB_SYSPLL_PCW_NCPO_M, 0x11c00000), + usbh + SSUSB_U3PHYA_3_REG); + + writel(FIELD_PREP(SSUSB_PCIE_CLKDRV_AMP_M, 4) | + FIELD_PREP(SSUSB_SYSPLL_FBSEL_M, 1) | + FIELD_PREP(SSUSB_SYSPLL_PREDIV_M, 1), + usbh + SSUSB_U3PHYA_1_REG); + + writel(FIELD_PREP(SSUSB_SYSPLL_FBDIV_M, 0x12) | + SSUSB_SYSPLL_VCO_DIV_SEL | SSUSB_SYSPLL_FPEN | + SSUSB_SYSPLL_MONCK_EN | SSUSB_SYSPLL_VOD_EN, + usbh + SSUSB_U3PHYA_2_REG); + + writel(SSUSB_EQ_CURSEL | FIELD_PREP(SSUSB_RX_DAC_MUX_M, 8) | + FIELD_PREP(SSUSB_PCIE_SIGDET_VTH_M, 1) | + FIELD_PREP(SSUSB_PCIE_SIGDET_LPF_M, 1), + usbh + SSUSB_U3PHYA_11_REG); + + writel(FIELD_PREP(SSUSB_RING_OSC_CNTEND_M, 0x1ff) | + FIELD_PREP(SSUSB_XTAL_OSC_CNTEND_M, 0x7f) | + SSUSB_RING_BYPASS_DET, + usbh + SSUSB_B2_ROSC_0_REG); + + writel(FIELD_PREP(SSUSB_RING_OSC_FRC_RECAL_M, 3) | + SSUSB_RING_OSC_FRC_SEL, + usbh + SSUSB_B2_ROSC_1_REG); +} + +static void xhci_config_25mhz(void __iomem *usbh) +{ + writel(FIELD_PREP(SSUSB_MAC3_SYS_CK_GATE_MASK_TIME_M, 0x20) | + FIELD_PREP(SSUSB_MAC2_SYS_CK_GATE_MASK_TIME_M, 0x20) | + FIELD_PREP(SSUSB_MAC3_SYS_CK_GATE_MODE_M, 2) | + FIELD_PREP(SSUSB_MAC2_SYS_CK_GATE_MODE_M, 2) | 0x10, + usbh + SSUSB_MAC_CK_CTRL_REG); + + writel(FIELD_PREP(SSUSB_PLL_PREDIV_PE1D_M, 2) | + FIELD_PREP(SSUSB_PLL_FBKDI_M, 4), + usbh + DA_SSUSB_U3PHYA_10_REG); + + writel(FIELD_PREP(SSUSB_PLL_FBKDIV_PE2H_M, 0x18) | + FIELD_PREP(SSUSB_PLL_FBKDIV_PE1D_M, 0x18) | + FIELD_PREP(SSUSB_PLL_FBKDIV_PE1H_M, 0x18) | + FIELD_PREP(SSUSB_PLL_FBKDIV_U3_M, 0x19), + usbh + DA_SSUSB_PLL_FBKDIV_REG); + + writel(FIELD_PREP(SSUSB_PLL_PCW_NCPO_U3_M, 0x18000000), + usbh + DA_SSUSB_PLL_PCW_NCPO_REG); + + writel(FIELD_PREP(SSUSB_PLL_SSC_DELTA1_PE1H_M, 0x25) | + FIELD_PREP(SSUSB_PLL_SSC_DELTA1_U3_M, 0x4a), + usbh + DA_SSUSB_PLL_SSC_DELTA1_REG); + + writel(FIELD_PREP(SSUSB_PLL_SSC_DELTA_U3_M, 0x48) | + FIELD_PREP(SSUSB_PLL_SSC_DELTA1_PE2D_M, 0x4a), + usbh + DA_SSUSB_U3PHYA_21_REG); + + writel(FIELD_PREP(SSUSB_PLL_SSC_PRD_M, 0x190), + usbh + SSUSB_U3PHYA_9_REG); + + writel(FIELD_PREP(SSUSB_SYSPLL_PCW_NCPO_M, 0xe000000), + usbh + SSUSB_U3PHYA_3_REG); + + writel(FIELD_PREP(SSUSB_PCIE_CLKDRV_AMP_M, 4) | + FIELD_PREP(SSUSB_SYSPLL_FBSEL_M, 1), + usbh + SSUSB_U3PHYA_1_REG); + + writel(FIELD_PREP(SSUSB_SYSPLL_FBDIV_M, 0xf) | + SSUSB_SYSPLL_VCO_DIV_SEL | SSUSB_SYSPLL_FPEN | + SSUSB_SYSPLL_MONCK_EN | SSUSB_SYSPLL_VOD_EN, + usbh + SSUSB_U3PHYA_2_REG); + + writel(SSUSB_EQ_CURSEL | FIELD_PREP(SSUSB_RX_DAC_MUX_M, 8) | + FIELD_PREP(SSUSB_PCIE_SIGDET_VTH_M, 1) | + FIELD_PREP(SSUSB_PCIE_SIGDET_LPF_M, 1), + usbh + SSUSB_U3PHYA_11_REG); + + writel(FIELD_PREP(SSUSB_RING_OSC_CNTEND_M, 0x1ff) | + FIELD_PREP(SSUSB_XTAL_OSC_CNTEND_M, 0x7f) | + SSUSB_RING_BYPASS_DET, + usbh + SSUSB_B2_ROSC_0_REG); + + writel(FIELD_PREP(SSUSB_RING_OSC_FRC_RECAL_M, 3) | + SSUSB_RING_OSC_FRC_SEL, + usbh + SSUSB_B2_ROSC_1_REG); +} + +void lowlevel_init(void) +{ + void __iomem *usbh = ioremap_nocache(SSUSB_BASE, SSUSB_SIZE); + u32 xtal = get_xtal_mhz(); + + /* Setup USB xHCI */ + if (xtal == 40) + xhci_config_40mhz(usbh); + else if (xtal == 25) + xhci_config_25mhz(usbh); +} + +ulong notrace get_tbclk(void) +{ + return gd->arch.timer_freq; +} + +void _machine_restart(void) +{ + void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE); + + while (1) + writel(SYS_RST, sysc + SYSCTL_RSTCTL_REG); +} diff --git a/arch/mips/mach-mtmips/mt7621/mt7621.h b/arch/mips/mach-mtmips/mt7621/mt7621.h new file mode 100644 index 00000000000..916cc993b47 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/mt7621.h @@ -0,0 +1,229 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#ifndef _MT7621_H_ +#define _MT7621_H_ + +#define SYSCTL_BASE 0x1e000000 +#define SYSCTL_SIZE 0x100 +#define TIMER_BASE 0x1e000100 +#define TIMER_SIZE 0x100 +#define RBUS_BASE 0x1e000400 +#define RBUS_SIZE 0x100 +#define GPIO_BASE 0x1e000600 +#define GPIO_SIZE 0x100 +#define DMA_CFG_ARB_BASE 0x1e000800 +#define DMA_CFG_ARB_SIZE 0x100 +#define SPI_BASE 0x1e000b00 +#define SPI_SIZE 0x100 +#define UART1_BASE 0x1e000c00 +#define UART1_SIZE 0x100 +#define UART2_BASE 0x1e000d00 +#define UART2_SIZE 0x100 +#define UART3_BASE 0x1e000e00 +#define UART3_SIZE 0x100 +#define NFI_BASE 0x1e003000 +#define NFI_SIZE 0x800 +#define NFI_ECC_BASE 0x1e003800 +#define NFI_ECC_SIZE 0x800 +#define DRAMC_BASE 0x1e005000 +#define DRAMC_SIZE 0x1000 +#define FE_BASE 0x1e100000 +#define FE_SIZE 0xe000 +#define GMAC_BASE 0x1e110000 +#define GMAC_SIZE 0x8000 +#define SSUSB_BASE 0x1e1c0000 +#define SSUSB_SIZE 0x40000 + + /* GIC Base Address */ +#define MIPS_GIC_BASE 0x1fbc0000 + + /* CPC Base Address */ +#define MIPS_CPC_BASE 0x1fbf0000 + + /* Flash Memory-mapped Base Address */ +#define FLASH_MMAP_BASE 0x1fc00000 +#define TPL_INFO_OFFSET 0x40 +#define TPL_INFO_MAGIC 0x31323637 /* Magic "7621" */ + +/* SRAM */ +#define FE_SRAM_BASE1 0x8000 +#define FE_SRAM_BASE2 0xa000 + +/* SYSCTL_BASE */ +#define SYSCTL_CHIP_REV_ID_REG 0x0c +#define CPU_ID 0x20000 +#define PKG_ID 0x10000 +#define VER_ID_S 8 +#define VER_ID_M 0xf00 +#define ECO_ID_S 0 +#define ECO_ID_M 0x0f + +#define SYSCTL_SYSCFG0_REG 0x10 +#define XTAL_MODE_SEL_S 6 +#define XTAL_MODE_SEL_M 0x1c0 +#define DRAM_TYPE 0x10 +#define CHIP_MODE_S 0 +#define CHIP_MODE_M 0x0f + +#define BOOT_SRAM_BASE_REG 0x20 + +#define SYSCTL_CLKCFG0_REG 0x2c +#define CPU_CLK_SEL_S 30 +#define CPU_CLK_SEL_M 0xc0000000 +#define MPLL_CFG_SEL_S 23 +#define MPLL_CFG_SEL_M 0x800000 + +#define SYSCTL_RSTCTL_REG 0x34 +#define MCM_RST 0x04 +#define SYS_RST 0x01 + +#define SYSCTL_CUR_CLK_STS_REG 0x44 +#define CUR_CPU_FDIV_S 8 +#define CUR_CPU_FDIV_M 0x1f00 +#define CUR_CPU_FFRAC_S 0 +#define CUR_CPU_FFRAC_M 0x1f + +#define SYSCTL_GPIOMODE_REG 0x60 +#define UART2_MODE_S 5 +#define UART2_MODE_M 0x60 +#define UART3_MODE_S 3 +#define UART3_MODE_M 0x18 +#define UART1_MODE 0x02 + +/* RBUS_BASE */ +#define RBUS_DYN_CFG0_REG 0x0010 +#define CPU_FDIV_S 8 +#define CPU_FDIV_M 0x1f00 +#define CPU_FFRAC_S 0 +#define CPU_FFRAC_M 0x1f + +/* DMA_CFG_ARB_BASE */ +#define DMA_ROUTE_REG 0x000c + +/* SPI_BASE */ +#define SPI_SPACE_REG 0x003c +#define FS_SLAVE_SEL_S 12 +#define FS_SLAVE_SEL_M 0x70000 +#define FS_CLK_SEL_S 0 +#define FS_CLK_SEL_M 0xfff + +/* FE_BASE */ +#define FE_RST_GLO_REG 0x0004 +#define FE_PSE_RAM 0x04 +#define FE_PSE_MEM_EN 0x02 +#define FE_PSE_RESET 0x01 + +/* SSUSB_BASE */ +#define SSUSB_MAC_CK_CTRL_REG 0x10784 +#define SSUSB_MAC3_SYS_CK_GATE_MASK_TIME_S 16 +#define SSUSB_MAC3_SYS_CK_GATE_MASK_TIME_M 0xff0000 +#define SSUSB_MAC2_SYS_CK_GATE_MASK_TIME_S 8 +#define SSUSB_MAC2_SYS_CK_GATE_MASK_TIME_M 0xff00 +#define SSUSB_MAC3_SYS_CK_GATE_MODE_S 2 +#define SSUSB_MAC3_SYS_CK_GATE_MODE_M 0x0c +#define SSUSB_MAC2_SYS_CK_GATE_MODE_S 0 +#define SSUSB_MAC2_SYS_CK_GATE_MODE_M 0x03 + +#define SSUSB_B2_ROSC_0_REG 0x10a40 +#define SSUSB_RING_OSC_CNTEND_S 23 +#define SSUSB_RING_OSC_CNTEND_M 0xff800000 +#define SSUSB_XTAL_OSC_CNTEND_S 16 +#define SSUSB_XTAL_OSC_CNTEND_M 0x7f0000 +#define SSUSB_RING_BYPASS_DET 0x01 + +#define SSUSB_B2_ROSC_1_REG 0x10a44 +#define SSUSB_RING_OSC_FRC_RECAL_S 17 +#define SSUSB_RING_OSC_FRC_RECAL_M 0x60000 +#define SSUSB_RING_OSC_FRC_SEL 0x01 + +#define SSUSB_U3PHYA_1_REG 0x10b04 +#define SSUSB_PCIE_CLKDRV_AMP_S 27 +#define SSUSB_PCIE_CLKDRV_AMP_M 0x38000000 +#define SSUSB_SYSPLL_FBSEL_S 2 +#define SSUSB_SYSPLL_FBSEL_M 0x0c +#define SSUSB_SYSPLL_PREDIV_S 0 +#define SSUSB_SYSPLL_PREDIV_M 0x03 + +#define SSUSB_U3PHYA_2_REG 0x10b08 +#define SSUSB_SYSPLL_FBDIV_S 24 +#define SSUSB_SYSPLL_FBDIV_M 0x7f000000 +#define SSUSB_SYSPLL_VCO_DIV_SEL 0x200000 +#define SSUSB_SYSPLL_FPEN 0x2000 +#define SSUSB_SYSPLL_MONCK_EN 0x1000 +#define SSUSB_SYSPLL_VOD_EN 0x200 + +#define SSUSB_U3PHYA_3_REG 0x10b10 +#define SSUSB_SYSPLL_PCW_NCPO_S 1 +#define SSUSB_SYSPLL_PCW_NCPO_M 0xfffffffe + +#define SSUSB_U3PHYA_9_REG 0x10b24 +#define SSUSB_PLL_SSC_PRD_S 0 +#define SSUSB_PLL_SSC_PRD_M 0xffff + +#define SSUSB_U3PHYA_11_REG 0x10b2c +#define SSUSB_EQ_CURSEL 0x1000000 +#define SSUSB_RX_DAC_MUX_S 19 +#define SSUSB_RX_DAC_MUX_M 0xf80000 +#define SSUSB_PCIE_SIGDET_VTH_S 5 +#define SSUSB_PCIE_SIGDET_VTH_M 0x60 +#define SSUSB_PCIE_SIGDET_LPF_S 3 +#define SSUSB_PCIE_SIGDET_LPF_M 0x18 + +#define DA_SSUSB_PLL_FBKDIV_REG 0x10c1c +#define SSUSB_PLL_FBKDIV_PE2H_S 24 +#define SSUSB_PLL_FBKDIV_PE2H_M 0x7f000000 +#define SSUSB_PLL_FBKDIV_PE1D_S 16 +#define SSUSB_PLL_FBKDIV_PE1D_M 0x7f0000 +#define SSUSB_PLL_FBKDIV_PE1H_S 8 +#define SSUSB_PLL_FBKDIV_PE1H_M 0x7f00 +#define SSUSB_PLL_FBKDIV_U3_S 0 +#define SSUSB_PLL_FBKDIV_U3_M 0x7f + +#define DA_SSUSB_U3PHYA_10_REG 0x10c20 +#define SSUSB_PLL_PREDIV_PE1D_S 18 +#define SSUSB_PLL_PREDIV_PE1D_M 0xc0000 +#define SSUSB_PLL_PREDIV_U3_S 8 +#define SSUSB_PLL_PREDIV_U3_M 0x300 +#define SSUSB_PLL_FBKDI_S 0 +#define SSUSB_PLL_FBKDI_M 0x07 + +#define DA_SSUSB_PLL_PCW_NCPO_REG 0x10c24 +#define SSUSB_PLL_PCW_NCPO_U3_S 0 +#define SSUSB_PLL_PCW_NCPO_U3_M 0x7fffffff + +#define DA_SSUSB_PLL_SSC_DELTA1_REG 0x10c38 +#define SSUSB_PLL_SSC_DELTA1_PE1H_S 16 +#define SSUSB_PLL_SSC_DELTA1_PE1H_M 0xffff0000 +#define SSUSB_PLL_SSC_DELTA1_U3_S 0 +#define SSUSB_PLL_SSC_DELTA1_U3_M 0xffff + +#define DA_SSUSB_U3PHYA_21_REG 0x10c40 +#define SSUSB_PLL_SSC_DELTA_U3_S 16 +#define SSUSB_PLL_SSC_DELTA_U3_M 0xffff0000 +#define SSUSB_PLL_SSC_DELTA1_PE2D_S 0 +#define SSUSB_PLL_SSC_DELTA1_PE2D_M 0xffff + +/* MT7621 specific CM values */ + +/* GCR_REGx_BASE */ +#define GCR_REG0_BASE_VALUE 0x1c000000 +#define GCR_REG1_BASE_VALUE 0x60000000 +#define GCR_REG2_BASE_VALUE 0x1c000000 +#define GCR_REG3_BASE_VALUE 0x1c000000 + +/* GCR_REGx_MASK */ +#define GCR_REG0_MASK_VALUE 0x0000fc00 /* 64M Bus */ +#define GCR_REG1_MASK_VALUE 0x0000f000 /* 256M PCI Mem */ +#define GCR_REG2_MASK_VALUE 0x0000fc00 /* unused */ +#define GCR_REG3_MASK_VALUE 0x0000fc00 /* unused */ + +#ifndef __ASSEMBLY__ +unsigned long get_xtal_mhz(void); +#endif + +#endif /* _MT7621_H_ */ diff --git a/arch/mips/mach-mtmips/mt7621/serial.c b/arch/mips/mach-mtmips/mt7621/serial.c new file mode 100644 index 00000000000..0ccc71dc756 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/serial.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <asm/io.h> +#include <asm/addrspace.h> +#include "mt7621.h" + +void board_debug_uart_init(void) +{ + void __iomem *base = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE); + +#if CONFIG_DEBUG_UART_BASE == 0xbe000c00 /* KSEG1ADDR(UART1_BASE) */ + clrbits_32(base + SYSCTL_GPIOMODE_REG, UART1_MODE); +#elif CONFIG_DEBUG_UART_BASE == 0xbe000d00 /* KSEG1ADDR(UART2_BASE) */ + clrbits_32(base + SYSCTL_GPIOMODE_REG, UART2_MODE_M); +#elif CONFIG_DEBUG_UART_BASE == 0xbe000e00 /* KSEG1ADDR(UART3_BASE) */ + clrbits_32(base + SYSCTL_GPIOMODE_REG, UART3_MODE_M); +#endif +} diff --git a/arch/mips/mach-mtmips/mt7621/spl/Makefile b/arch/mips/mach-mtmips/mt7621/spl/Makefile new file mode 100644 index 00000000000..ebe54e79b90 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/Makefile @@ -0,0 +1,9 @@ + +extra-y += start.o + +obj-y += spl.o +obj-y += cps.o +obj-y += dram.o +obj-y += serial.o +obj-y += launch.o +obj-y += launch_ll.o diff --git a/arch/mips/mach-mtmips/mt7621/spl/cps.c b/arch/mips/mach-mtmips/mt7621/spl/cps.c new file mode 100644 index 00000000000..779e646c126 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/cps.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <asm/io.h> +#include <asm/addrspace.h> +#include <asm/mipsregs.h> +#include <asm/cm.h> +#include <linux/bitfield.h> +#include "../mt7621.h" + +/* GIC Shared Register Bases */ +#define GIC_SH_POL_BASE 0x100 +#define GIC_SH_TRIG_BASE 0x180 +#define GIC_SH_RMASK_BASE 0x300 +#define GIC_SH_SMASK_BASE 0x380 +#define GIC_SH_MASK_BASE 0x400 +#define GIC_SH_PEND_BASE 0x480 +#define GIC_SH_MAP_PIN_BASE 0x500 +#define GIC_SH_MAP_VPE_BASE 0x2000 + +/* GIC Registers */ +#define GIC_SH_POL31_0 (GIC_SH_POL_BASE + 0x00) +#define GIC_SH_POL63_32 (GIC_SH_POL_BASE + 0x04) + +#define GIC_SH_TRIG31_0 (GIC_SH_TRIG_BASE + 0x00) +#define GIC_SH_TRIG63_32 (GIC_SH_TRIG_BASE + 0x04) + +#define GIC_SH_RMASK31_0 (GIC_SH_RMASK_BASE + 0x00) +#define GIC_SH_RMASK63_32 (GIC_SH_RMASK_BASE + 0x04) + +#define GIC_SH_SMASK31_0 (GIC_SH_SMASK_BASE + 0x00) +#define GIC_SH_SMASK63_32 (GIC_SH_SMASK_BASE + 0x04) + +#define GIC_SH_MAP_PIN(n) (GIC_SH_MAP_PIN_BASE + (n) * 4) + +#define GIC_SH_MAP_VPE(n, v) (GIC_SH_MAP_VPE_BASE + (n) * 0x20 + ((v) / 32) * 4) +#define GIC_SH_MAP_VPE31_0(n) GIC_SH_MAP_VPE(n, 0) + +/* GIC_SH_MAP_PIN fields */ +#define GIC_MAP_TO_PIN BIT(31) +#define GIC_MAP_TO_NMI BIT(30) +#define GIC_MAP GENMASK(5, 0) +#define GIC_MAP_SHIFT 0 + +static void cm_init(void __iomem *cm_base) +{ + u32 gcrcfg, num_cores; + + gcrcfg = readl(cm_base + GCR_CONFIG); + num_cores = FIELD_GET(GCR_CONFIG_PCORES, gcrcfg) + 1; + + writel((1 << num_cores) - 1, cm_base + GCR_ACCESS); + + writel(GCR_REG0_BASE_VALUE, cm_base + GCR_REG0_BASE); + writel(GCR_REG1_BASE_VALUE, cm_base + GCR_REG1_BASE); + writel(GCR_REG2_BASE_VALUE, cm_base + GCR_REG2_BASE); + writel(GCR_REG3_BASE_VALUE, cm_base + GCR_REG3_BASE); + + clrsetbits_32(cm_base + GCR_REG0_MASK, + GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT, + FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG0_MASK_VALUE) | + GCR_REGn_MASK_CMTGT_IOCU0); + + clrsetbits_32(cm_base + GCR_REG1_MASK, + GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT, + FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG1_MASK_VALUE) | + GCR_REGn_MASK_CMTGT_IOCU0); + + clrsetbits_32(cm_base + GCR_REG2_MASK, + GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT, + FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG2_MASK_VALUE) | + GCR_REGn_MASK_CMTGT_IOCU0); + + clrsetbits_32(cm_base + GCR_REG3_MASK, + GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT, + FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG3_MASK_VALUE) | + GCR_REGn_MASK_CMTGT_IOCU0); + + clrbits_32(cm_base + GCR_BASE, CM_DEFAULT_TARGET_MASK); + setbits_32(cm_base + GCR_CONTROL, GCR_CONTROL_SYNCCTL); +} + +static void gic_init(void) +{ + void __iomem *gic_base = (void *)KSEG1ADDR(MIPS_GIC_BASE); + int i; + + /* Interrupt 0..5: Level Trigger, Active High */ + writel(0, gic_base + GIC_SH_TRIG31_0); + writel(0x3f, gic_base + GIC_SH_RMASK31_0); + writel(0x3f, gic_base + GIC_SH_POL31_0); + writel(0x3f, gic_base + GIC_SH_SMASK31_0); + + /* Interrupt 56..63: Edge Trigger, Rising Edge */ + /* Hardcoded to set up the last 8 external interrupts for IPI. */ + writel(0xff000000, gic_base + GIC_SH_TRIG63_32); + writel(0xff000000, gic_base + GIC_SH_RMASK63_32); + writel(0xff000000, gic_base + GIC_SH_POL63_32); + writel(0xff000000, gic_base + GIC_SH_SMASK63_32); + + /* Map interrupt source to particular hardware interrupt pin */ + /* source {0,1,2,3,4,5} -> pin {0,0,4,3,0,5} */ + writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(0)); + writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(1)); + writel(GIC_MAP_TO_PIN | 4, gic_base + GIC_SH_MAP_PIN(2)); + writel(GIC_MAP_TO_PIN | 3, gic_base + GIC_SH_MAP_PIN(3)); + writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(4)); + writel(GIC_MAP_TO_PIN | 5, gic_base + GIC_SH_MAP_PIN(5)); + + /* source 56~59 -> pin 1, 60~63 -> pin 2 */ + writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(56)); + writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(57)); + writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(58)); + writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(59)); + writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(60)); + writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(61)); + writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(62)); + writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(63)); + + /* Interrupt map to VPE (bit mask) */ + for (i = 0; i < 32; i++) + writel(BIT(0), gic_base + GIC_SH_MAP_VPE31_0(i)); + + /* + * Direct GIC_int 56..63 to vpe 0..3 + * MIPS Linux convention that last 16 interrupts implemented be set + * aside for IPI signaling. + * The actual interrupts are tied low and software sends interrupts + * via GIC_SH_WEDGE writes. + */ + for (i = 0; i < 4; i++) { + writel(BIT(i), gic_base + GIC_SH_MAP_VPE31_0(i + 56)); + writel(BIT(i), gic_base + GIC_SH_MAP_VPE31_0(i + 60)); + } +} + +void mt7621_cps_init(void) +{ + void __iomem *cm_base = (void *)KSEG1ADDR(CONFIG_MIPS_CM_BASE); + + /* Enable GIC */ + writel(MIPS_GIC_BASE | GCR_GIC_EN, cm_base + GCR_GIC_BASE); + + /* Enable CPC */ + writel(MIPS_CPC_BASE | GCR_CPC_EN, cm_base + GCR_CPC_BASE); + + gic_init(); + cm_init(cm_base); +} diff --git a/arch/mips/mach-mtmips/mt7621/spl/dram.c b/arch/mips/mach-mtmips/mt7621/spl/dram.c new file mode 100644 index 00000000000..100adfb93a5 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/dram.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <vsprintf.h> +#include <asm/io.h> +#include <asm/sections.h> +#include <asm/byteorder.h> +#include <asm/addrspace.h> +#include <linux/string.h> +#include "../mt7621.h" +#include "dram.h" + +static const u32 ddr2_act[DDR_PARAM_SIZE] = { +#if defined(CONFIG_MT7621_DRAM_DDR2_512M) + 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x22174441, + 0x00000000, 0xF0748661, 0x40001273, 0x9F0A0481, + 0x0304692F, 0x15602842, 0x00008888, 0x88888888, + 0x00000000, 0x00000000, 0x00000000, 0x07100000, + 0x00001B63, 0x00002000, 0x00004000, 0x00006000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +#elif defined(CONFIG_MT7621_DRAM_DDR2_512M_W9751G6KB_A02_1066MHZ) + 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x33484584, + 0x00000000, 0xF07486A1, 0x50001273, 0x9F010481, + 0x0304693F, 0x15602842, 0x00008888, 0x88888888, + 0x00000000, 0x00000000, 0x00000010, 0x07100000, + 0x00001F73, 0x00002000, 0x00004000, 0x00006000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +#elif defined(CONFIG_MT7621_DRAM_DDR2_1024M_W971GG6KB25_800MHZ) + 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x22174430, + 0x01000000, 0xF0748661, 0x40001273, 0x9F0F0481, + 0x0304692F, 0x15602842, 0x00008888, 0x88888888, + 0x00000000, 0x00000000, 0x00000000, 0x07100000, + 0x00001B63, 0x00002000, 0x00004000, 0x00006000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +#elif defined(CONFIG_MT7621_DRAM_DDR2_1024M_W971GG6KB18_1066MHZ) + 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x33484584, + 0x01000000, 0xF07486A1, 0x50001273, 0x9F070481, + 0x0304693F, 0x15602842, 0x00008888, 0x88888888, + 0x00000000, 0x00000000, 0x00000010, 0x07100000, + 0x00001F73, 0x00002000, 0x00004000, 0x00006000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +#else /* CONFIG_MT7621_DRAM_DDR2_1024M */ + 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x22174441, + 0x01000000, 0xF0748661, 0x40001273, 0x9F0F0481, + 0x0304692F, 0x15602842, 0x00008888, 0x88888888, + 0x00000000, 0x00000000, 0x00000000, 0x07100000, + 0x00001B63, 0x00002000, 0x00004000, 0x00006000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +#endif +}; + +static const u32 ddr3_act[DDR_PARAM_SIZE] = { +#if defined(CONFIG_MT7621_DRAM_DDR3_1024M) + 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x44694683, + 0x01000000, 0xF07486A1, 0xC287221D, 0x9F060481, + 0x03046948, 0x15602842, 0x00008888, 0x88888888, + 0x00000000, 0x00000000, 0x00000210, 0x07100000, + 0x00001B61, 0x00002040, 0x00004010, 0x00006000, + 0x0C000000, 0x07070000, 0x00000000, 0x00000000, +#elif defined(CONFIG_MT7621_DRAM_DDR3_4096M) + 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x44694683, + 0x01000000, 0xF07486A1, 0xC287221D, 0x9F0F0481, + 0x03046948, 0x15602842, 0x00008888, 0x88888888, + 0x00000000, 0x00000000, 0x00000240, 0x07100000, + 0x00001B61, 0x00002040, 0x00004010, 0x00006000, + 0x0C000000, 0x07070000, 0x00000000, 0x00000000, +#elif defined(CONFIG_MT7621_DRAM_DDR3_1024M_KGD) + 0xFF00FF00, 0xFF00FF00, 0x00000007, 0x44694683, + 0x01000000, 0xF07406A1, 0xC287221D, 0x9F060481, + 0x03046923, 0x152f2842, 0x00008888, 0x88888888, + 0x00000000, 0x00000000, 0x00000210, 0x07100000, + 0x00001B61, 0x00002040, 0x00004010, 0x00006000, + 0x0C000000, 0x07070000, 0x000C0000, 0x00000000, +#else /* CONFIG_MT7621_DRAM_DDR3_2048M */ + 0xAA00AA00, 0xAA00AA00, 0x00000007, 0x44694673, + 0x01000000, 0xF07486A1, 0xC287221D, 0x9F050481, + 0x03046948, 0x15602842, 0x00008888, 0x88888888, + 0x00000000, 0x00000000, 0x00000220, 0x07100000, + 0x00001B61, 0x00002040, 0x00004010, 0x00006000, + 0x0C000000, 0x07070000, 0x00000000, 0x00000000, +#endif +}; + +#if defined(CONFIG_MT7621_DRAM_FREQ_400) +#define DDR_FREQ_PARAM 0x41000000 +#elif defined(CONFIG_MT7621_DRAM_FREQ_1066) +#define DDR_FREQ_PARAM 0x21000000 +#elif defined(CONFIG_MT7621_DRAM_FREQ_1200) +#define DDR_FREQ_PARAM 0x11000000 +#else /* CONFIG_MT7621_DRAM_FREQ_800 */ +#define DDR_FREQ_PARAM 0x31000000 +#endif + +#define RG_MEPL_FBDIV_S 4 +#define RG_MEPL_FBDIV_M 0x7f + +static inline void word_copy(u32 *dest, const u32 *src, u32 count) +{ + u32 i; + + for (i = 0; i < count; i++) + dest[i] = src[i]; +} + +static u32 calc_cpu_pll_val(void) +{ + u32 div, baseval, fb; + + div = get_xtal_mhz(); + + if (div == 40) { + div /= 2; + baseval = 0xc0005802; + } else { + baseval = 0xc0004802; + } + + fb = CONFIG_MT7621_CPU_FREQ / div - 1; + if (fb > RG_MEPL_FBDIV_M) + fb = RG_MEPL_FBDIV_M; + + return baseval | (fb << RG_MEPL_FBDIV_S); +} + +void prepare_stage_bin(void) +{ + u32 stage_size; + + const struct stage_header *stock_stage_bin = + (const struct stage_header *)__image_copy_end; + + struct stage_header *new_stage_bin = + (struct stage_header *)STAGE_LOAD_ADDR; + + if (be32_to_cpu(stock_stage_bin->ep) != STAGE_LOAD_ADDR) + panic("Invalid DDR stage binary blob\n"); + + stage_size = be32_to_cpu(stock_stage_bin->stage_size); + + word_copy((u32 *)new_stage_bin, (const u32 *)stock_stage_bin, + (stage_size + sizeof(u32) - 1) / sizeof(u32)); + + word_copy(new_stage_bin->ddr2_act, ddr2_act, DDR_PARAM_SIZE); + word_copy(new_stage_bin->ddr3_act, ddr3_act, DDR_PARAM_SIZE); + + new_stage_bin->cpu_pll_cfg = calc_cpu_pll_val(); + new_stage_bin->ddr_pll_cfg = DDR_FREQ_PARAM; + new_stage_bin->baudrate = CONFIG_BAUDRATE; +} diff --git a/arch/mips/mach-mtmips/mt7621/spl/dram.h b/arch/mips/mach-mtmips/mt7621/spl/dram.h new file mode 100644 index 00000000000..7322c58276a --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/dram.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#ifndef _MT7621_DRAM_H_ +#define _MT7621_DRAM_H_ + +#define STAGE_LOAD_ADDR 0xBE108800 + +#ifndef __ASSEMBLY__ +#include <linux/types.h> + +#define DDR_PARAM_SIZE 24 + +struct stage_header { + u32 jump_insn[2]; + u32 ep; + u32 stage_size; + u32 has_stage2; + u32 next_ep; + u32 next_size; + u32 next_offset; + u32 cpu_pll_cfg; + u32 ddr_pll_cfg; + u32 reserved2[6]; + char build_tag[32]; + u32 ddr3_act[DDR_PARAM_SIZE]; + u32 padding1[2]; + u32 ddr2_act[DDR_PARAM_SIZE]; + u32 padding2[2]; + u32 baudrate; + u32 padding3; +}; +#endif + +#endif /* _MT7621_DRAM_H_ */ diff --git a/arch/mips/mach-mtmips/mt7621/spl/launch.c b/arch/mips/mach-mtmips/mt7621/spl/launch.c new file mode 100644 index 00000000000..37c20a5f564 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/launch.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <asm/io.h> +#include <asm/cm.h> +#include <asm/sections.h> +#include <asm/addrspace.h> +#include <asm/mipsmtregs.h> +#include <linux/sizes.h> +#include <time.h> +#include <cpu_func.h> +#include "launch.h" +#include "../mt7621.h" + +/* Cluster Power Controller (CPC) offsets */ +#define CPC_CL_OTHER 0x2010 +#define CPC_CO_CMD 0x4000 + +/* CPC_CL_OTHER fields */ +#define CPC_CL_OTHER_CORENUM_SHIFT 16 +#define CPC_CL_OTHER_CORENUM GENMASK(23, 16) + +/* CPC_CO_CMD */ +#define PWR_UP 3 + +#define NUM_CORES 2 +#define NUM_CPUS 4 +#define WAIT_CPUS_TIMEOUT 4000 + +static void copy_launch_wait_code(void) +{ + memset((void *)KSEG1, 0, SZ_4K); + + memcpy((void *)KSEG1ADDR(LAUNCH_WAITCODE), + &launch_wait_code_start, + &launch_wait_code_end - &launch_wait_code_start); + + invalidate_dcache_range(KSEG0, SZ_4K); +} + +static void bootup_secondary_core(void) +{ + void __iomem *cpcbase = (void __iomem *)KSEG1ADDR(MIPS_CPC_BASE); + int i; + + for (i = 1; i < NUM_CORES; i++) { + writel(i << CPC_CL_OTHER_CORENUM_SHIFT, cpcbase + CPC_CL_OTHER); + writel(PWR_UP, cpcbase + CPC_CO_CMD); + } +} + +void secondary_cpu_init(void) +{ + void __iomem *sysc = (void __iomem *)KSEG1ADDR(SYSCTL_BASE); + u32 i, dual_core = 0, cpuready = 1, cpumask = 0x03; + ulong wait_tick; + struct cpulaunch_t *c; + + /* Copy LAUNCH wait code used by other VPEs */ + copy_launch_wait_code(); + + dual_core = readl(sysc + SYSCTL_CHIP_REV_ID_REG) & CPU_ID; + + if (dual_core) { + /* Bootup secondary core for MT7621A */ + cpumask = 0x0f; + + /* Make BootROM/TPL redirect Core1's bootup flow to our entry point */ + writel((uintptr_t)&_start, sysc + BOOT_SRAM_BASE_REG); + + bootup_secondary_core(); + } + + /* Join the coherent domain */ + join_coherent_domain(dual_core ? 2 : 1); + + /* Bootup Core0/VPE1 */ + boot_vpe1(); + + /* Wait for all CPU ready */ + wait_tick = get_timer(0) + WAIT_CPUS_TIMEOUT; + + while (time_before(get_timer(0), wait_tick)) { + /* CPU0 is obviously ready */ + for (i = 1; i < NUM_CPUS; i++) { + c = (struct cpulaunch_t *)(KSEG0ADDR(CPULAUNCH) + + (i << LOG2CPULAUNCH)); + + if (c->flags & LAUNCH_FREADY) + cpuready |= BIT(i); + } + + if ((cpuready & cpumask) == cpumask) + break; + } +} diff --git a/arch/mips/mach-mtmips/mt7621/spl/launch.h b/arch/mips/mach-mtmips/mt7621/spl/launch.h new file mode 100644 index 00000000000..f34250d6058 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/launch.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#ifndef _LAUNCH_H_ +#define _LAUNCH_H_ + +#ifndef __ASSEMBLY__ + +struct cpulaunch_t { + unsigned long pc; + unsigned long gp; + unsigned long sp; + unsigned long a0; + unsigned long _pad[3]; /* pad to cache line size to avoid thrashing */ + unsigned long flags; +}; + +extern char launch_wait_code_start; +extern char launch_wait_code_end; + +void join_coherent_domain(int ncores); +void boot_vpe1(void); + +#else + +#define LAUNCH_PC 0 +#define LAUNCH_GP 4 +#define LAUNCH_SP 8 +#define LAUNCH_A0 12 +#define LAUNCH_FLAGS 28 + +#endif + +#define LOG2CPULAUNCH 5 + +#define LAUNCH_FREADY 1 +#define LAUNCH_FGO 2 +#define LAUNCH_FGONE 4 + +#define LAUNCH_WAITCODE 0x00000d00 +#define SCRLAUNCH 0x00000e00 +#define CPULAUNCH 0x00000f00 +#define NCPULAUNCH 8 + +/* Polling period in count cycles for secondary CPU's */ +#define LAUNCHPERIOD 10000 + +#endif /* _LAUNCH_H_ */ diff --git a/arch/mips/mach-mtmips/mt7621/spl/launch_ll.S b/arch/mips/mach-mtmips/mt7621/spl/launch_ll.S new file mode 100644 index 00000000000..32d28c7539a --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/launch_ll.S @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <asm/cm.h> +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/cacheops.h> +#include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/mipsmtregs.h> +#include "launch.h" + + .macro cache_loop curr, end, line_sz, op +10: cache \op, 0(\curr) + PTR_ADDU \curr, \curr, \line_sz + bne \curr, \end, 10b + .endm + + .set mt + +/* + * Join the coherent domain + * a0 = number of cores + */ +LEAF(join_coherent_domain) + /* + * Enable coherence and allow interventions from all other cores. + * (Write access enabled via GCR_ACCESS by core 0.) + */ + li t1, 1 + sll t1, a0 + addiu t1, -1 + + li t0, KSEG1ADDR(CONFIG_MIPS_CM_BASE) + sw t1, GCR_Cx_COHERENCE(t0) + ehb + + move t2, zero + +_next_coherent_core: + sll t1, t2, GCR_Cx_OTHER_CORENUM_SHIFT + sw t1, GCR_Cx_OTHER(t0) + +_busy_wait_coherent_core: + lw t1, GCR_CO_COHERENCE(t0) + beqz t1, _busy_wait_coherent_core + + addiu t2, 1 + bne t2, a0, _next_coherent_core + + jr ra + END(join_coherent_domain) + +/* + * All VPEs other than VPE0 will go here. + */ +LEAF(launch_vpe_entry) + mfc0 t0, CP0_EBASE + and t0, t0, MIPS_EBASE_CPUNUM + + /* per-VPE cpulaunch_t */ + li a0, KSEG0ADDR(CPULAUNCH) + sll t1, t0, LOG2CPULAUNCH + addu a0, t1 + + /* Set CPU online flag */ + li t0, LAUNCH_FREADY + sw t0, LAUNCH_FLAGS(a0) + + /* Enable count interrupt in mask, but do not enable interrupts */ + mfc0 t0, CP0_STATUS + ori t0, STATUSF_IP7 + mtc0 t0, CP0_STATUS + + /* VPEs executing in wait code do not need a stack */ + li t9, KSEG0ADDR(LAUNCH_WAITCODE) + jr t9 + END(launch_vpe_entry) + +/* + * This function will not be executed in place. + * It will be copied into memory, and VPEs other than VPE0 will be + * started to run into this in-memory function. + */ +LEAF(launch_wait_code) + .globl launch_wait_code_start +launch_wait_code_start: + + move t0, a0 + +start_poll: + /* Poll CPU go flag */ + mtc0 zero, CP0_COUNT + li t1, LAUNCHPERIOD + mtc0 t1, CP0_COMPARE + +time_wait: + /* Software wait */ + mfc0 t2, CP0_COUNT + subu t2, t1 + bltz t2, time_wait + + /* Check the launch flag */ + lw t3, LAUNCH_FLAGS(t0) + and t3, LAUNCH_FGO + beqz t3, start_poll + + /* Reset the counter and interrupts to give naive clients a chance */ + mfc0 t1, CP0_STATUS + ins t1, zero, STATUSB_IP7, 1 + mtc0 t1, CP0_STATUS + + mfc0 t1, CP0_COUNT + subu t1, 1 + mtc0 t1, CP0_COMPARE + + /* Jump to kernel */ + lw t9, LAUNCH_PC(t0) + lw gp, LAUNCH_GP(t0) + lw sp, LAUNCH_SP(t0) + lw a0, LAUNCH_A0(t0) + move a1, zero + move a2, zero + move a3, zero + ori t3, LAUNCH_FGONE + sw t3, LAUNCH_FLAGS(t0) + + jr t9 + + .globl launch_wait_code_end +launch_wait_code_end: + END(launch_wait_code) + +/* + * Core1 will go here. + */ +LEAF(launch_core_entry) + /* Disable caches */ + bal mips_cache_disable + + /* Initialize L1 cache only */ + li a0, CONFIG_SYS_ICACHE_SIZE + li a1, CONFIG_SYS_ICACHE_LINE_SIZE + li a2, CONFIG_SYS_DCACHE_SIZE + li a3, CONFIG_SYS_DCACHE_LINE_SIZE + + mtc0 zero, CP0_TAGLO + mtc0 zero, CP0_TAGLO, 2 + ehb + + /* + * Initialize the I-cache first, + */ + li t0, KSEG0 + addu t1, t0, a0 + /* clear tag to invalidate */ + cache_loop t0, t1, a1, INDEX_STORE_TAG_I +#ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD + /* fill once, so data field parity is correct */ + PTR_LI t0, KSEG0 + cache_loop t0, t1, a1, FILL + /* invalidate again - prudent but not strictly necessary */ + PTR_LI t0, KSEG0 + cache_loop t0, t1, a1, INDEX_STORE_TAG_I +#endif + + /* + * then initialize D-cache. + */ + PTR_LI t0, KSEG0 + PTR_ADDU t1, t0, a2 + /* clear all tags */ + cache_loop t0, t1, a3, INDEX_STORE_TAG_D +#ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD + /* load from each line (in cached space) */ + PTR_LI t0, KSEG0 +2: LONG_L zero, 0(t0) + PTR_ADDU t0, a3 + bne t0, t1, 2b + /* clear all tags */ + PTR_LI t0, KSEG0 + cache_loop t0, t1, a3, INDEX_STORE_TAG_D +#endif + + /* Set Cache Mode */ + mfc0 t0, CP0_CONFIG + li t1, CONF_CM_CACHABLE_COW + ins t0, t1, 0, 3 + mtc0 t0, CP0_CONFIG + + /* Join the coherent domain */ + li a0, 2 + bal join_coherent_domain + + /* Bootup Core0/VPE1 */ + bal boot_vpe1 + + b launch_vpe_entry + END(launch_core_entry) + +/* + * Bootup VPE1. + * This subroutine must be executed from VPE0 with VPECONF0[MVP] already set. + */ +LEAF(boot_vpe1) + mfc0 t0, CP0_MVPCONF0 + + /* a0 = number of TCs - 1 */ + ext a0, t0, MVPCONF0_PTC_SHIFT, 8 + beqz a0, _vpe1_init_done + + /* a1 = number of VPEs - 1 */ + ext a1, t0, MVPCONF0_PVPE_SHIFT, 4 + beqz a1, _vpe1_init_done + + /* a2 = current TC No. */ + move a2, zero + + /* Enter VPE Configuration State */ + mfc0 t0, CP0_MVPCONTROL + or t0, MVPCONTROL_VPC + mtc0 t0, CP0_MVPCONTROL + ehb + +_next_tc: + /* Set the TC number to be used on MTTR and MFTR instructions */ + mfc0 t0, CP0_VPECONTROL + ins t0, a2, 0, 8 + mtc0 t0, CP0_VPECONTROL + ehb + + /* TC0 is already bound */ + beqz a2, _next_vpe + + /* Halt current TC */ + li t0, TCHALT_H + mttc0 t0, CP0_TCHALT + ehb + + /* If there is spare TC, bind it to the last VPE (VPE[a1]) */ + slt t1, a1, a2 + bnez t1, _vpe_bind_tc + move t1, a1 + + /* Set Exclusive TC for active TC */ + mftc0 t0, CP0_VPECONF0 + ins t0, a2, VPECONF0_XTC_SHIFT, 8 + mttc0 t0, CP0_VPECONF0 + + move t1, a2 +_vpe_bind_tc: + /* Bind TC to a VPE */ + mftc0 t0, CP0_TCBIND + ins t0, t1, TCBIND_CURVPE_SHIFT, 4 + mttc0 t0, CP0_TCBIND + + /* + * Set up CP0_TCSTATUS register: + * Disable Coprocessor Usable bits + * Disable MDMX/DSP ASE + * Clear Dirty TC + * not dynamically allocatable + * not allocated + * Kernel mode + * interrupt exempt + * ASID 0 + */ + li t0, TCSTATUS_IXMT + mttc0 t0, CP0_TCSTATUS + +_next_vpe: + slt t1, a1, a2 + bnez t1, _done_vpe # No more VPEs + + /* Disable TC multi-threading */ + mftc0 t0, CP0_VPECONTROL + ins t0, zero, VPECONTROL_TE_SHIFT, 1 + mttc0 t0, CP0_VPECONTROL + + /* Skip following configuration for TC0 */ + beqz a2, _done_vpe + + /* Deactivate VPE, set Master VPE */ + mftc0 t0, CP0_VPECONF0 + ins t0, zero, VPECONF0_VPA_SHIFT, 1 + or t0, VPECONF0_MVP + mttc0 t0, CP0_VPECONF0 + + mfc0 t0, CP0_STATUS + mttc0 t0, CP0_STATUS + + mttc0 zero, CP0_EPC + mttc0 zero, CP0_CAUSE + + mfc0 t0, CP0_CONFIG + mttc0 t0, CP0_CONFIG + + /* + * VPE1 of each core can execute cached as its L1 I$ has already + * been initialized. + * and the L2$ has been initialized or "disabled" via CCA override. + */ + PTR_LA t0, _start + mttc0 t0, CP0_TCRESTART + + /* Unset Interrupt Exempt, set Activate Thread */ + mftc0 t0, CP0_TCSTATUS + ins t0, zero, TCSTATUS_IXMT_SHIFT, 1 + ori t0, TCSTATUS_A + mttc0 t0, CP0_TCSTATUS + + /* Resume TC */ + mttc0 zero, CP0_TCHALT + + /* Activate VPE */ + mftc0 t0, CP0_VPECONF0 + ori t0, VPECONF0_VPA + mttc0 t0, CP0_VPECONF0 + +_done_vpe: + addu a2, 1 + sltu t0, a0, a2 + beqz t0, _next_tc + + mfc0 t0, CP0_MVPCONTROL + /* Enable all activated VPE to execute */ + ori t0, MVPCONTROL_EVP + /* Exit VPE Configuration State */ + ins t0, zero, MVPCONTROL_VPC_SHIFT, 1 + mtc0 t0, CP0_MVPCONTROL + ehb + +_vpe1_init_done: + jr ra + END(boot_vpe1) diff --git a/arch/mips/mach-mtmips/mt7621/spl/serial.c b/arch/mips/mach-mtmips/mt7621/spl/serial.c new file mode 100644 index 00000000000..5cf093a078a --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/serial.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <asm/io.h> +#include "../mt7621.h" + +void mtmips_spl_serial_init(void) +{ +#ifdef CONFIG_SPL_SERIAL + void __iomem *base = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE); + +#if CONFIG_CONS_INDEX == 1 + clrbits_32(base + SYSCTL_GPIOMODE_REG, UART1_MODE); +#elif CONFIG_CONS_INDEX == 2 + clrbits_32(base + SYSCTL_GPIOMODE_REG, UART2_MODE_M); +#elif CONFIG_CONS_INDEX == 3 + clrbits_32(base + SYSCTL_GPIOMODE_REG, UART3_MODE_M); +#endif /* CONFIG_CONS_INDEX */ +#endif /* CONFIG_SPL_SERIAL */ +} diff --git a/arch/mips/mach-mtmips/mt7621/spl/spl.c b/arch/mips/mach-mtmips/mt7621/spl/spl.c new file mode 100644 index 00000000000..91eebc6c1fb --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/spl.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <init.h> +#include <image.h> +#include <vsprintf.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/sections.h> +#include <asm/addrspace.h> +#include <asm/byteorder.h> +#include <asm/global_data.h> +#include <linux/sizes.h> +#include <linux/types.h> +#include <mach/serial.h> +#include "../mt7621.h" +#include "dram.h" +#include <spl.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct tpl_info { + u32 magic; + u32 size; +}; + +void set_timer_freq_simple(void) +{ + u32 div = get_xtal_mhz(); + + /* Round down cpu freq */ + gd->arch.timer_freq = rounddown(CONFIG_MT7621_CPU_FREQ, div) * 500000; +} + +void __noreturn board_init_f(ulong dummy) +{ + spl_init(); + +#ifdef CONFIG_SPL_SERIAL + /* + * mtmips_spl_serial_init() is useful if debug uart is enabled, + * or DM based serial is not enabled. + */ + mtmips_spl_serial_init(); + preloader_console_init(); +#endif + + board_init_r(NULL, 0); +} + +void board_boot_order(u32 *spl_boot_list) +{ +#ifdef CONFIG_MT7621_BOOT_FROM_NAND + spl_boot_list[0] = BOOT_DEVICE_NAND; +#else + spl_boot_list[0] = BOOT_DEVICE_NOR; +#endif +} + +unsigned long spl_nor_get_uboot_base(void) +{ + const struct tpl_info *tpli; + const image_header_t *hdr; + u32 addr; + + addr = FLASH_MMAP_BASE + TPL_INFO_OFFSET; + tpli = (const struct tpl_info *)KSEG1ADDR(addr); + + if (tpli->magic == TPL_INFO_MAGIC) { + addr = FLASH_MMAP_BASE + tpli->size; + hdr = (const image_header_t *)KSEG1ADDR(addr); + + if (image_get_magic(hdr) == IH_MAGIC) { + addr += sizeof(*hdr) + image_get_size(hdr); + return KSEG1ADDR(addr); + } + } + + panic("Unable to locate SPL payload\n"); + return 0; +} + +uint32_t spl_nand_get_uboot_raw_page(void) +{ + const struct stage_header *sh = (const struct stage_header *)&_start; + u32 addr; + + addr = image_get_header_size() + be32_to_cpu(sh->stage_size); + addr = ALIGN(addr, SZ_4K); + + return addr; +} diff --git a/arch/mips/mach-mtmips/mt7621/spl/start.S b/arch/mips/mach-mtmips/mt7621/spl/start.S new file mode 100644 index 00000000000..3cad3567e72 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/spl/start.S @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <asm-offsets.h> +#include <config.h> +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/mipsregs.h> +#include <asm/cacheops.h> +#include <asm/addrspace.h> +#include <asm/mipsmtregs.h> +#include <asm/cm.h> +#include "../mt7621.h" +#include "dram.h" + +#ifndef CONFIG_SYS_INIT_SP_ADDR +#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + \ + CONFIG_SYS_INIT_SP_OFFSET) +#endif + +#define SP_ADDR_TEMP 0xbe10dff0 + + .macro init_wr sel + MTC0 zero, CP0_WATCHLO,\sel + mtc0 t1, CP0_WATCHHI,\sel + .endm + + .macro setup_stack_gd + li t0, -16 + PTR_LI t1, CONFIG_SYS_INIT_SP_ADDR + and sp, t1, t0 # force 16 byte alignment + PTR_SUBU \ + sp, sp, GD_SIZE # reserve space for gd + and sp, sp, t0 # force 16 byte alignment + move k0, sp # save gd pointer +#if CONFIG_VAL(SYS_MALLOC_F_LEN) && \ + !CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F) + li t2, CONFIG_VAL(SYS_MALLOC_F_LEN) + PTR_SUBU \ + sp, sp, t2 # reserve space for early malloc + and sp, sp, t0 # force 16 byte alignment +#endif + move fp, sp + + /* Clear gd */ + move t0, k0 +1: + PTR_S zero, 0(t0) + PTR_ADDIU t0, PTRSIZE + blt t0, t1, 1b + nop + +#if CONFIG_VAL(SYS_MALLOC_F_LEN) && \ + !CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F) + PTR_S sp, GD_MALLOC_BASE(k0) # gd->malloc_base offset +#endif + .endm + + .set noreorder + +ENTRY(_start) + b 1f + mtc0 zero, CP0_COUNT + + /* Stage header required by BootROM */ + .org 0x8 + .word 0 # ep, filled by mkimage + .word 0 # stage_size, filled by mkimage + .word 0 # has_stage2 + .word 0 # next_ep + .word 0 # next_size + .word 0 # next_offset + +1: + /* Init CP0 Status */ + mfc0 t0, CP0_STATUS + and t0, ST0_IMPL + or t0, ST0_BEV | ST0_ERL + mtc0 t0, CP0_STATUS + ehb + + /* Clear Watch Status bits and disable watch exceptions */ + li t1, 0x7 # Clear I, R and W conditions + init_wr 0 + init_wr 1 + init_wr 2 + init_wr 3 + + /* Clear WP, IV and SW interrupts */ + mtc0 zero, CP0_CAUSE + + /* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */ + mtc0 zero, CP0_COMPARE + + /* VPE1 goes to wait code directly */ + mfc0 t0, CP0_TCBIND + andi t0, TCBIND_CURVPE + bnez t0, launch_vpe_entry + nop + + /* Core1 goes to specific launch entry */ + PTR_LI t0, KSEG1ADDR(CONFIG_MIPS_CM_BASE) + lw t1, GCR_Cx_ID(t0) + bnez t1, launch_core_entry + nop + + /* MT7530 reset */ + li t0, KSEG1ADDR(SYSCTL_BASE) + lw t1, SYSCTL_RSTCTL_REG(t0) + ori t1, MCM_RST + sw t1, SYSCTL_RSTCTL_REG(t0) + + /* Disable DMA route for PSE SRAM set by BootROM */ + PTR_LI t0, KSEG1ADDR(DMA_CFG_ARB_BASE) + sw zero, DMA_ROUTE_REG(t0) + + /* Set CPU clock to 500MHz (Required if boot from NAND) */ + li t0, KSEG1ADDR(SYSCTL_BASE) + lw t1, SYSCTL_CLKCFG0_REG(t0) + ins t1, zero, 30, 2 # CPU_CLK_SEL + sw t1, SYSCTL_CLKCFG0_REG(t0) + + /* Set CPU clock divider to 1/1 */ + li t0, KSEG1ADDR(RBUS_BASE) + li t1, 0x101 + sw t1, RBUS_DYN_CFG0_REG(t0) + + /* (Re-)initialize the SRAM */ + bal mips_sram_init + nop + + /* Set up temporary stack */ + li sp, SP_ADDR_TEMP + + /* Setup full CPS */ + bal mips_cm_map + nop + + bal mt7621_cps_init + nop + + /* Prepare for CPU/DDR initialization binary blob */ + bal prepare_stage_bin + nop + + /* Call CPU/DDR initialization binary blob */ + li t9, STAGE_LOAD_ADDR + jalr t9 + nop + + /* Switch CPU PLL source */ + li t0, KSEG1ADDR(SYSCTL_BASE) + lw t1, SYSCTL_CLKCFG0_REG(t0) + li t2, 1 + ins t1, t2, CPU_CLK_SEL_S, 2 + sw t1, SYSCTL_CLKCFG0_REG(t0) + + /* + * Currently SPL is running on locked L2 cache (on KSEG0). + * To reset the entire cache, we have to writeback SPL to DRAM first. + * Cache flush won't work here. Use memcpy instead. + */ + + la a0, __text_start + move a1, a0 + la a2, __image_copy_end + sub a2, a2, a1 + li a3, 5 + ins a0, a3, 29, 3 # convert to KSEG1 + + bal memcpy + nop + + /* Disable caches */ + bal mips_cache_disable + nop + + /* Reset caches */ + bal mips_cache_reset + nop + + /* Disable SRAM */ + li t0, KSEG1ADDR(FE_BASE) + li t1, FE_PSE_RESET + sw t1, FE_RST_GLO_REG(t0) + + /* Clear the .bss section */ + la a0, __bss_start + la a1, __bss_end +1: sw zero, 0(a0) + addiu a0, 4 + ble a0, a1, 1b + nop + + /* Set up initial stack and global data */ + setup_stack_gd + +#if CONFIG_IS_ENABLED(INIT_STACK_WITHOUT_MALLOC_F) + /* Set malloc base */ + li t0, (CONFIG_SYS_INIT_SP_ADDR + 15) & (~15) + PTR_S t0, GD_MALLOC_BASE(k0) # gd->malloc_base offset +#endif + +#if defined(CONFIG_DEBUG_UART) && defined(CONFIG_SPL_SERIAL) + /* Earliest point to set up debug uart */ + bal debug_uart_init + nop +#endif + + /* Setup timer */ + bal set_timer_freq_simple + nop + + /* Bootup secondary CPUs */ + bal secondary_cpu_init + nop + + move a0, zero # a0 <-- boot_flags = 0 + bal board_init_f + move ra, zero + + END(_start) diff --git a/arch/mips/mach-mtmips/mt7621/sram_init.S b/arch/mips/mach-mtmips/mt7621/sram_init.S new file mode 100644 index 00000000000..03b9eab10b1 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/sram_init.S @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <asm/addrspace.h> +#include <asm/asm.h> +#include <asm/regdef.h> +#include "mt7621.h" + +LEAF(mips_sram_init) + li t0, KSEG1ADDR(FE_BASE) + li t1, FE_PSE_RESET + sw t1, FE_RST_GLO_REG(t0) + + li t1, (FE_PSE_RAM | FE_PSE_MEM_EN) + sw t1, FE_RST_GLO_REG(t0) + + jr ra + END(mips_sram_init) diff --git a/arch/mips/mach-mtmips/mt7621/tpl/Makefile b/arch/mips/mach-mtmips/mt7621/tpl/Makefile new file mode 100644 index 00000000000..471ad74249a --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/tpl/Makefile @@ -0,0 +1,4 @@ + +extra-y += start.o + +obj-y += tpl.o diff --git a/arch/mips/mach-mtmips/mt7621/tpl/start.S b/arch/mips/mach-mtmips/mt7621/tpl/start.S new file mode 100644 index 00000000000..19b09f72513 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/tpl/start.S @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <asm-offsets.h> +#include <config.h> +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/addrspace.h> +#include <asm/mipsregs.h> +#include <asm/cm.h> +#include "../mt7621.h" + +#define SP_ADDR_TEMP 0xbe10dff0 + + .set noreorder + + .macro init_wr sel + MTC0 zero, CP0_WATCHLO,\sel + mtc0 t1, CP0_WATCHHI,\sel + .endm + + .macro uhi_mips_exception + move k0, t9 # preserve t9 in k0 + move k1, a0 # preserve a0 in k1 + li t9, 15 # UHI exception operation + li a0, 0 # Use hard register context + sdbbp 1 # Invoke UHI operation + .endm + +ENTRY(_start) + b reset + mtc0 zero, CP0_COUNT + + /* + * Store TPL size here. + * This will be used by SPL to locate u-boot payload. + */ + .org TPL_INFO_OFFSET + .word TPL_INFO_MAGIC + .word __image_copy_len + + /* Exception vector */ + .org 0x200 + /* TLB refill, 32 bit task */ + uhi_mips_exception + + .org 0x280 + /* XTLB refill, 64 bit task */ + uhi_mips_exception + + .org 0x300 + /* Cache error exception */ + uhi_mips_exception + + .org 0x380 + /* General exception */ + uhi_mips_exception + + .org 0x400 + /* Catch interrupt exceptions */ + uhi_mips_exception + + .org 0x480 + /* EJTAG debug exception */ +1: b 1b + nop + + .org 0x500 + +reset: + /* Set KSEG0 to Uncached */ + mfc0 t0, CP0_CONFIG + ins t0, zero, 0, 3 + ori t0, t0, CONF_CM_UNCACHED + mtc0 t0, CP0_CONFIG + ehb + + /* Check for CPU number */ + mfc0 t0, CP0_EBASE + and t0, t0, MIPS_EBASE_CPUNUM + beqz t0, 1f + nop + + /* Secondary core goes to specified SPL entry address */ + li t0, KSEG1ADDR(SYSCTL_BASE) + lw t0, BOOT_SRAM_BASE_REG(t0) + jr t0 + nop + + /* Init CP0 Status */ +1: mfc0 t0, CP0_STATUS + and t0, ST0_IMPL + or t0, ST0_BEV | ST0_ERL + mtc0 t0, CP0_STATUS + nop + + /* Clear Watch Status bits and disable watch exceptions */ + li t1, 0x7 # Clear I, R and W conditions + init_wr 0 + init_wr 1 + init_wr 2 + init_wr 3 + + /* Clear WP, IV and SW interrupts */ + mtc0 zero, CP0_CAUSE + + /* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */ + mtc0 zero, CP0_COMPARE + + /* Setup basic CPS */ + bal mips_cm_map + nop + + li t0, KSEG1ADDR(CONFIG_MIPS_CM_BASE) + li t1, GCR_REG0_BASE_VALUE + sw t1, GCR_REG0_BASE(t0) + + li t1, ((GCR_REG0_MASK_VALUE << GCR_REGn_MASK_ADDRMASK_SHIFT) | \ + GCR_REGn_MASK_CMTGT_IOCU0) + sw t1, GCR_REG0_MASK(t0) + + lw t1, GCR_BASE(t0) + ins t1, zero, 0, 2 # CM_DEFAULT_TARGET + sw t1, GCR_BASE(t0) + + lw t1, GCR_CONTROL(t0) + li t2, GCR_CONTROL_SYNCCTL + or t1, t1, t2 + sw t1, GCR_CONTROL(t0) + + /* Increase SPI frequency */ + li t0, KSEG1ADDR(SPI_BASE) + li t1, 5 + sw t1, SPI_SPACE_REG(t0) + + /* Set CPU clock to 500MHz */ + li t0, KSEG1ADDR(SYSCTL_BASE) + lw t1, SYSCTL_CLKCFG0_REG(t0) + ins t1, zero, 30, 2 # CPU_CLK_SEL + sw t1, SYSCTL_CLKCFG0_REG(t0) + + /* Set CPU clock divider to 1/1 */ + li t0, KSEG1ADDR(RBUS_BASE) + li t1, 0x101 + sw t1, RBUS_DYN_CFG0_REG(t0) + + /* Initialize the SRAM */ + bal mips_sram_init + nop + + /* Set up initial stack */ + li sp, SP_ADDR_TEMP + + bal tpl_main + nop + + END(_start) diff --git a/arch/mips/mach-mtmips/mt7621/tpl/tpl.c b/arch/mips/mach-mtmips/mt7621/tpl/tpl.c new file mode 100644 index 00000000000..2a828907a34 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/tpl/tpl.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <image.h> +#include <asm/system.h> +#include <asm/sections.h> +#include <asm/cacheops.h> +#include <asm/mipsregs.h> +#include <asm/cm.h> + +#define INDEX_STORE_DATA_SD 0x0f + +typedef void __noreturn (*image_entry_noargs_t)(void); + +/* + * Lock L2 cache and fill data + * Assume that data is 4-byte aligned and start_addr/size is 32-byte aligned + */ +static void fill_lock_l2cache(uintptr_t dataptr, ulong start_addr, ulong size) +{ + ulong slsize = CONFIG_SYS_DCACHE_LINE_SIZE; + ulong end_addr = start_addr + size; + const u32 *data = (u32 *)dataptr; + ulong i, addr; + u32 val; + + /* Clear WSC & SPR bit in ErrCtl */ + val = read_c0_ecc(); + val &= 0xcfffffff; + write_c0_ecc(val); + execution_hazard_barrier(); + + for (addr = start_addr; addr < end_addr; addr += slsize) { + /* Set STagLo to lock cache line */ + write_c0_staglo((addr & 0x1ffff800) | 0xa0); + mips_cache(INDEX_STORE_TAG_SD, (void *)addr); + + /* Fill data */ + for (i = 0; i < slsize; i += 8) { + val = *data++; + __write_32bit_c0_register($28, 5, val); /* sdtaglo */ + val = *data++; + __write_32bit_c0_register($29, 5, val); /* sdtaghi */ + mips_cache(INDEX_STORE_DATA_SD, (void *)(addr + i)); + } + } + + sync(); +} + +/* A simple function to initialize MT7621's cache */ +static void mt7621_cache_init(void) +{ + void __iomem *cm_base = (void *)KSEG1ADDR(CONFIG_MIPS_CM_BASE); + ulong lsize = CONFIG_SYS_DCACHE_LINE_SIZE; + ulong addr; + u32 val; + + /* Enable CCA override. Set to uncached */ + val = readl(cm_base + GCR_BASE); + val &= ~CCA_DEFAULT_OVR_MASK; + val |= CCA_DEFAULT_OVREN | (2 << CCA_DEFAULT_OVR_SHIFT); + writel(val, cm_base + GCR_BASE); + + /* Initialize L1 I-Cache */ + write_c0_taglo(0); + write_c0_taghi(0); + + for (addr = 0; addr < CONFIG_SYS_ICACHE_SIZE; addr += lsize) + mips_cache(INDEX_STORE_TAG_I, (void *)addr); + + /* Initialize L1 D-Cache */ + write_c0_dtaglo(0); + __write_32bit_c0_register($29, 2, 0); /* dtaghi */ + + for (addr = 0; addr < CONFIG_SYS_DCACHE_SIZE; addr += lsize) + mips_cache(INDEX_STORE_TAG_D, (void *)addr); + + /* Initialize L2 Cache */ + write_c0_staglo(0); + __write_32bit_c0_register($29, 4, 0); /* staghi */ + + for (addr = 0; addr < (256 << 10); addr += lsize) + mips_cache(INDEX_STORE_TAG_SD, (void *)addr); + + /* Dsiable CCA override */ + val = readl(cm_base + GCR_BASE); + val &= ~(CCA_DEFAULT_OVR_MASK | CCA_DEFAULT_OVREN); + writel(val, cm_base + GCR_BASE); + + /* Set KSEG0 to non-coherent cached (important!) */ + val = read_c0_config(); + val &= ~CONF_CM_CMASK; + val |= CONF_CM_CACHABLE_NONCOHERENT; + write_c0_config(val); + execution_hazard_barrier(); + + /* Again, invalidate L1 D-Cache */ + for (addr = 0; addr < CONFIG_SYS_DCACHE_SIZE; addr += lsize) + mips_cache(INDEX_WRITEBACK_INV_D, (void *)addr); + + /* Invalidate L1 I-Cache */ + for (addr = 0; addr < CONFIG_SYS_ICACHE_SIZE; addr += lsize) + mips_cache(INDEX_INVALIDATE_I, (void *)addr); + + /* Disable L2 cache bypass */ + val = read_c0_config2(); + val &= ~MIPS_CONF_IMPL; + write_c0_config2(val); + execution_hazard_barrier(); +} + +void __noreturn tpl_main(void) +{ + const image_header_t *hdr = (const image_header_t *)__image_copy_end; + image_entry_noargs_t image_entry; + u32 loadaddr, size; + uintptr_t data; + + /* Initialize the cache first */ + mt7621_cache_init(); + + if (image_get_magic(hdr) != IH_MAGIC) + goto failed; + + loadaddr = image_get_load(hdr); + size = image_get_size(hdr); + image_entry = (image_entry_noargs_t)image_get_ep(hdr); + + /* Load TPL image to L2 cache */ + data = (uintptr_t)__image_copy_end + sizeof(struct image_header); + fill_lock_l2cache(data, loadaddr, size); + + /* Jump to SPL */ + image_entry(); + +failed: + for (;;) + ; +} |