diff options
author | Tom Rini | 2022-07-14 07:18:33 -0400 |
---|---|---|
committer | Tom Rini | 2022-07-14 07:18:33 -0400 |
commit | 58f3dc5c4eac9c6050edda6af2e37d20a2f9586d (patch) | |
tree | 78f091f787b36104ea2e2e42fee9b335a7915daa | |
parent | 854d6de6107bca044db362612f39691f4f5395ca (diff) | |
parent | dd6bf539e88aff1b8caeeccbe9af59b2191a178b (diff) |
Merge tag 'mips-pull-2022-07-13' of https://source.denx.de/u-boot/custodians/u-boot-mips
- MIPS: add drivers and board support for Mediatek MT7621 SoC
69 files changed, 5879 insertions, 36 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 2515ce7da3a..b85629d9b10 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1032,15 +1032,23 @@ R: GSS_MTK_Uboot_upstream <GSS_MTK_Uboot_upstream@mediatek.com> S: Maintained F: arch/mips/mach-mtmips/ F: arch/mips/dts/mt7620.dtsi +F: arch/mips/dts/mt7621.dtsi F: arch/mips/dts/mt7620-u-boot.dtsi +F: arch/mips/dts/mt7621-u-boot.dtsi F: include/configs/mt7620.h +F: include/configs/mt7621.h F: include/dt-bindings/clock/mt7620-clk.h +F: include/dt-bindings/clock/mt7621-clk.h F: include/dt-bindings/clock/mt7628-clk.h F: include/dt-bindings/reset/mt7620-reset.h +F: include/dt-bindings/reset/mt7621-reset.h F: include/dt-bindings/reset/mt7628-reset.h F: drivers/clk/mtmips/ F: drivers/pinctrl/mtmips/ F: drivers/gpio/mt7620_gpio.c +F: drivers/mtd/nand/raw/mt7621_nand.c +F: drivers/mtd/nand/raw/mt7621_nand.h +F: drivers/mtd/nand/raw/mt7621_nand_spl.c F: drivers/net/mt7620-eth.c F: drivers/phy/mt7620-usb-phy.c F: drivers/reset/reset-mtmips.c 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/cpu/u-boot-spl.lds b/arch/mips/cpu/u-boot-spl.lds index 194398be853..310a5c5053b 100644 --- a/arch/mips/cpu/u-boot-spl.lds +++ b/arch/mips/cpu/u-boot-spl.lds @@ -13,7 +13,9 @@ SECTIONS . = ALIGN(4); .text : { + __text_start = .; *(.text*) + __text_end = .; } > .spl_mem . = ALIGN(4); @@ -36,6 +38,7 @@ SECTIONS . = ALIGN(4); __image_copy_end = .; + __image_copy_len = __image_copy_end - __text_start; _image_binary_end = .; diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile index 95144b24dcf..1b179116c9b 100644 --- a/arch/mips/dts/Makefile +++ b/arch/mips/dts/Makefile @@ -16,6 +16,8 @@ dtb-$(CONFIG_BOARD_COMTREND_WAP5813N) += comtrend,wap-5813n.dtb dtb-$(CONFIG_BOARD_HUAWEI_HG556A) += huawei,hg556a.dtb dtb-$(CONFIG_BOARD_MT7620_RFB) += mediatek,mt7620-rfb.dtb dtb-$(CONFIG_BOARD_MT7620_MT7530_RFB) += mediatek,mt7620-mt7530-rfb.dtb +dtb-$(CONFIG_BOARD_MT7621_RFB) += mediatek,mt7621-rfb.dtb +dtb-$(CONFIG_BOARD_MT7621_NAND_RFB) += mediatek,mt7621-nand-rfb.dtb dtb-$(CONFIG_BOARD_MT7628_RFB) += mediatek,mt7628-rfb.dtb dtb-$(CONFIG_BOARD_GARDENA_SMART_GATEWAY_MT7688) += gardena-smart-gateway-mt7688.dtb dtb-$(CONFIG_BOARD_LINKIT_SMART_7688) += linkit-smart-7688.dtb diff --git a/arch/mips/dts/mediatek,mt7621-nand-rfb.dts b/arch/mips/dts/mediatek,mt7621-nand-rfb.dts new file mode 100644 index 00000000000..67ba298b0a6 --- /dev/null +++ b/arch/mips/dts/mediatek,mt7621-nand-rfb.dts @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +/dts-v1/; + +#include "mt7621.dtsi" + +/ { + compatible = "mediatek,mt7621-nand-rfb", "mediatek,mt7621-soc"; + model = "MediaTek MT7621 RFB (NAND)"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = &uart0; + }; +}; + +&pinctrl { + state_default: pin_state { + nand { + groups = "spi", "sdxc"; + function = "nand"; + }; + + gpios { + groups = "i2c", "uart3", "pcie reset"; + function = "gpio"; + }; + + wdt { + groups = "wdt"; + function = "wdt rst"; + }; + + jtag { + groups = "jtag"; + function = "jtag"; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +ð { + status = "okay"; +}; + +&ssusb { + status = "okay"; +}; + +&u3phy { + status = "okay"; +}; diff --git a/arch/mips/dts/mediatek,mt7621-rfb.dts b/arch/mips/dts/mediatek,mt7621-rfb.dts new file mode 100644 index 00000000000..ff7eaf0f20e --- /dev/null +++ b/arch/mips/dts/mediatek,mt7621-rfb.dts @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +/dts-v1/; + +#include "mt7621.dtsi" + +/ { + compatible = "mediatek,mt7621-rfb", "mediatek,mt7621-soc"; + model = "MediaTek MT7621 RFB (SPI-NOR)"; + + aliases { + serial0 = &uart0; + spi0 = &spi; + }; + + chosen { + stdout-path = &uart0; + }; +}; + +&pinctrl { + state_default: pin_state { + gpios { + groups = "i2c", "uart3", "pcie reset"; + function = "gpio"; + }; + + wdt { + groups = "wdt"; + function = "wdt rst"; + }; + + jtag { + groups = "jtag"; + function = "jtag"; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +&gpio { + status = "okay"; +}; + +&spi { + status = "okay"; + num-cs = <2>; + + spi-flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + spi-max-frequency = <25000000>; + reg = <0>; + }; +}; + +ð { + status = "okay"; +}; + +&mmc { + cap-sd-highspeed; + + status = "okay"; +}; + +&ssusb { + status = "okay"; +}; + +&u3phy { + status = "okay"; +}; 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/include/asm/cm.h b/arch/mips/include/asm/cm.h index 99ddbccd808..5cc8c09621d 100644 --- a/arch/mips/include/asm/cm.h +++ b/arch/mips/include/asm/cm.h @@ -8,9 +8,23 @@ #define __MIPS_ASM_CM_H__ /* Global Control Register (GCR) offsets */ +#define GCR_CONFIG 0x0000 #define GCR_BASE 0x0008 #define GCR_BASE_UPPER 0x000c +#define GCR_CONTROL 0x0010 +#define GCR_ACCESS 0x0020 #define GCR_REV 0x0030 +#define GCR_GIC_BASE 0x0080 +#define GCR_CPC_BASE 0x0088 +#define GCR_REG0_BASE 0x0090 +#define GCR_REG0_MASK 0x0098 +#define GCR_REG1_BASE 0x00a0 +#define GCR_REG1_MASK 0x00a8 +#define GCR_REG2_BASE 0x00b0 +#define GCR_REG2_MASK 0x00b8 +#define GCR_REG3_BASE 0x00c0 +#define GCR_REG3_MASK 0x00c8 +#define GCR_CPC_STATUS 0x00f0 #define GCR_L2_CONFIG 0x0130 #define GCR_L2_TAG_ADDR 0x0600 #define GCR_L2_TAG_ADDR_UPPER 0x0604 @@ -19,10 +33,59 @@ #define GCR_L2_DATA 0x0610 #define GCR_L2_DATA_UPPER 0x0614 #define GCR_Cx_COHERENCE 0x2008 +#define GCR_Cx_OTHER 0x2018 +#define GCR_Cx_ID 0x2028 +#define GCR_CO_COHERENCE 0x4008 + +/* GCR_CONFIG fields */ +#define GCR_CONFIG_NUM_CLUSTERS_SHIFT 23 +#define GCR_CONFIG_NUM_CLUSTERS (0x7f << 23) +#define GCR_CONFIG_NUMIOCU_SHIFT 8 +#define GCR_CONFIG_NUMIOCU (0xff << 8) +#define GCR_CONFIG_PCORES_SHIFT 0 +#define GCR_CONFIG_PCORES (0xff << 0) + +/* GCR_BASE fields */ +#define GCR_BASE_SHIFT 15 +#define CCA_DEFAULT_OVR_SHIFT 5 +#define CCA_DEFAULT_OVR_MASK (0x7 << 5) +#define CCA_DEFAULT_OVREN (0x1 << 4) +#define CM_DEFAULT_TARGET_SHIFT 0 +#define CM_DEFAULT_TARGET_MASK (0x3 << 0) + +/* GCR_CONTROL fields */ +#define GCR_CONTROL_SYNCCTL (0x1 << 16) /* GCR_REV CM versions */ #define GCR_REV_CM3 0x0800 +/* GCR_GIC_BASE fields */ +#define GCR_GIC_BASE_ADDRMASK_SHIFT 7 +#define GCR_GIC_BASE_ADDRMASK (0x1ffffff << 7) +#define GCR_GIC_EN (0x1 << 0) + +/* GCR_CPC_BASE fields */ +#define GCR_CPC_BASE_ADDRMASK_SHIFT 15 +#define GCR_CPC_BASE_ADDRMASK (0x1ffff << 15) +#define GCR_CPC_EN (0x1 << 0) + +/* GCR_REGn_MASK fields */ +#define GCR_REGn_MASK_ADDRMASK_SHIFT 16 +#define GCR_REGn_MASK_ADDRMASK (0xffff << 16) +#define GCR_REGn_MASK_CCAOVR_SHIFT 5 +#define GCR_REGn_MASK_CCAOVR (0x7 << 5) +#define GCR_REGn_MASK_CCAOVREN (1 << 4) +#define GCR_REGn_MASK_DROPL2 (1 << 2) +#define GCR_REGn_MASK_CMTGT_SHIFT 0 +#define GCR_REGn_MASK_CMTGT (0x3 << 0) +#define GCR_REGn_MASK_CMTGT_DISABLED 0x0 +#define GCR_REGn_MASK_CMTGT_MEM 0x1 +#define GCR_REGn_MASK_CMTGT_IOCU0 0x2 +#define GCR_REGn_MASK_CMTGT_IOCU1 0x3 + +/* GCR_CPC_STATUS fields */ +#define GCR_CPC_EX (0x1 << 0) + /* GCR_L2_CONFIG fields */ #define GCR_L2_CONFIG_ASSOC_SHIFT 0 #define GCR_L2_CONFIG_ASSOC_BITS 8 @@ -36,6 +99,10 @@ #define GCR_Cx_COHERENCE_DOM_EN (0xff << 0) #define GCR_Cx_COHERENCE_EN (0x1 << 0) +/* GCR_Cx_OTHER fields */ +#define GCR_Cx_OTHER_CORENUM_SHIFT 16 +#define GCR_Cx_OTHER_CORENUM (0xffff << 16) + #ifndef __ASSEMBLY__ #include <asm/io.h> diff --git a/arch/mips/include/asm/mipsmtregs.h b/arch/mips/include/asm/mipsmtregs.h new file mode 100644 index 00000000000..ba82e2bd977 --- /dev/null +++ b/arch/mips/include/asm/mipsmtregs.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * MT regs definitions, follows on from mipsregs.h + * Copyright (C) 2004 - 2005 MIPS Technologies, Inc. All rights reserved. + * Elizabeth Clarke et. al. + * + */ +#ifndef _ASM_MIPSMTREGS_H +#define _ASM_MIPSMTREGS_H + +#include <asm/mipsregs.h> + +/* + * Macros for use in assembly language code + */ + +#define CP0_MVPCONTROL $0, 1 +#define CP0_MVPCONF0 $0, 2 +#define CP0_MVPCONF1 $0, 3 +#define CP0_VPECONTROL $1, 1 +#define CP0_VPECONF0 $1, 2 +#define CP0_VPECONF1 $1, 3 +#define CP0_YQMASK $1, 4 +#define CP0_VPESCHEDULE $1, 5 +#define CP0_VPESCHEFBK $1, 6 +#define CP0_TCSTATUS $2, 1 +#define CP0_TCBIND $2, 2 +#define CP0_TCRESTART $2, 3 +#define CP0_TCHALT $2, 4 +#define CP0_TCCONTEXT $2, 5 +#define CP0_TCSCHEDULE $2, 6 +#define CP0_TCSCHEFBK $2, 7 +#define CP0_SRSCONF0 $6, 1 +#define CP0_SRSCONF1 $6, 2 +#define CP0_SRSCONF2 $6, 3 +#define CP0_SRSCONF3 $6, 4 +#define CP0_SRSCONF4 $6, 5 + +/* MVPControl fields */ +#define MVPCONTROL_EVP (_ULCAST_(1)) + +#define MVPCONTROL_VPC_SHIFT 1 +#define MVPCONTROL_VPC (_ULCAST_(1) << MVPCONTROL_VPC_SHIFT) + +#define MVPCONTROL_STLB_SHIFT 2 +#define MVPCONTROL_STLB (_ULCAST_(1) << MVPCONTROL_STLB_SHIFT) + +/* MVPConf0 fields */ +#define MVPCONF0_PTC_SHIFT 0 +#define MVPCONF0_PTC (_ULCAST_(0xff)) +#define MVPCONF0_PVPE_SHIFT 10 +#define MVPCONF0_PVPE (_ULCAST_(0xf) << MVPCONF0_PVPE_SHIFT) +#define MVPCONF0_TCA_SHIFT 15 +#define MVPCONF0_TCA (_ULCAST_(1) << MVPCONF0_TCA_SHIFT) +#define MVPCONF0_PTLBE_SHIFT 16 +#define MVPCONF0_PTLBE (_ULCAST_(0x3ff) << MVPCONF0_PTLBE_SHIFT) +#define MVPCONF0_TLBS_SHIFT 29 +#define MVPCONF0_TLBS (_ULCAST_(1) << MVPCONF0_TLBS_SHIFT) +#define MVPCONF0_M_SHIFT 31 +#define MVPCONF0_M (_ULCAST_(0x1) << MVPCONF0_M_SHIFT) + +/* config3 fields */ +#define CONFIG3_MT_SHIFT 2 +#define CONFIG3_MT (_ULCAST_(1) << CONFIG3_MT_SHIFT) + +/* VPEControl fields (per VPE) */ +#define VPECONTROL_TARGTC (_ULCAST_(0xff)) + +#define VPECONTROL_TE_SHIFT 15 +#define VPECONTROL_TE (_ULCAST_(1) << VPECONTROL_TE_SHIFT) +#define VPECONTROL_EXCPT_SHIFT 16 +#define VPECONTROL_EXCPT (_ULCAST_(0x7) << VPECONTROL_EXCPT_SHIFT) + +/* Thread Exception Codes for EXCPT field */ +#define THREX_TU 0 +#define THREX_TO 1 +#define THREX_IYQ 2 +#define THREX_GSX 3 +#define THREX_YSCH 4 +#define THREX_GSSCH 5 + +#define VPECONTROL_GSI_SHIFT 20 +#define VPECONTROL_GSI (_ULCAST_(1) << VPECONTROL_GSI_SHIFT) +#define VPECONTROL_YSI_SHIFT 21 +#define VPECONTROL_YSI (_ULCAST_(1) << VPECONTROL_YSI_SHIFT) + +/* VPEConf0 fields (per VPE) */ +#define VPECONF0_VPA_SHIFT 0 +#define VPECONF0_VPA (_ULCAST_(1) << VPECONF0_VPA_SHIFT) +#define VPECONF0_MVP_SHIFT 1 +#define VPECONF0_MVP (_ULCAST_(1) << VPECONF0_MVP_SHIFT) +#define VPECONF0_XTC_SHIFT 21 +#define VPECONF0_XTC (_ULCAST_(0xff) << VPECONF0_XTC_SHIFT) + +/* VPEConf1 fields (per VPE) */ +#define VPECONF1_NCP1_SHIFT 0 +#define VPECONF1_NCP1 (_ULCAST_(0xff) << VPECONF1_NCP1_SHIFT) +#define VPECONF1_NCP2_SHIFT 10 +#define VPECONF1_NCP2 (_ULCAST_(0xff) << VPECONF1_NCP2_SHIFT) +#define VPECONF1_NCX_SHIFT 20 +#define VPECONF1_NCX (_ULCAST_(0xff) << VPECONF1_NCX_SHIFT) + +/* TCStatus fields (per TC) */ +#define TCSTATUS_TASID (_ULCAST_(0xff)) +#define TCSTATUS_IXMT_SHIFT 10 +#define TCSTATUS_IXMT (_ULCAST_(1) << TCSTATUS_IXMT_SHIFT) +#define TCSTATUS_TKSU_SHIFT 11 +#define TCSTATUS_TKSU (_ULCAST_(3) << TCSTATUS_TKSU_SHIFT) +#define TCSTATUS_A_SHIFT 13 +#define TCSTATUS_A (_ULCAST_(1) << TCSTATUS_A_SHIFT) +#define TCSTATUS_DA_SHIFT 15 +#define TCSTATUS_DA (_ULCAST_(1) << TCSTATUS_DA_SHIFT) +#define TCSTATUS_DT_SHIFT 20 +#define TCSTATUS_DT (_ULCAST_(1) << TCSTATUS_DT_SHIFT) +#define TCSTATUS_TDS_SHIFT 21 +#define TCSTATUS_TDS (_ULCAST_(1) << TCSTATUS_TDS_SHIFT) +#define TCSTATUS_TSST_SHIFT 22 +#define TCSTATUS_TSST (_ULCAST_(1) << TCSTATUS_TSST_SHIFT) +#define TCSTATUS_RNST_SHIFT 23 +#define TCSTATUS_RNST (_ULCAST_(3) << TCSTATUS_RNST_SHIFT) +/* Codes for RNST */ +#define TC_RUNNING 0 +#define TC_WAITING 1 +#define TC_YIELDING 2 +#define TC_GATED 3 + +#define TCSTATUS_TMX_SHIFT 27 +#define TCSTATUS_TMX (_ULCAST_(1) << TCSTATUS_TMX_SHIFT) +/* TCStatus TCU bits can use same definitions/offsets as CU bits in Status */ + +/* TCBind */ +#define TCBIND_CURVPE_SHIFT 0 +#define TCBIND_CURVPE (_ULCAST_(0xf)) + +#define TCBIND_CURTC_SHIFT 21 + +#define TCBIND_CURTC (_ULCAST_(0xff) << TCBIND_CURTC_SHIFT) + +/* TCHalt */ +#define TCHALT_H (_ULCAST_(1)) + +#endif diff --git a/arch/mips/include/asm/system.h b/arch/mips/include/asm/system.h index 79e638844b2..89a2ac209fc 100644 --- a/arch/mips/include/asm/system.h +++ b/arch/mips/include/asm/system.h @@ -282,4 +282,24 @@ static inline void instruction_hazard_barrier(void) : "=&r"(tmp)); } +#ifdef CONFIG_SYS_NONCACHED_MEMORY +/* 1MB granularity */ +#define MMU_SECTION_SHIFT 20 +#define MMU_SECTION_SIZE (1 << MMU_SECTION_SHIFT) + +/** + * noncached_init() - Initialize non-cached memory region + * + * Initialize non-cached memory area. This memory region will be typically + * located right below the malloc() area and be accessed from KSEG1. + * + * It is called during the generic post-relocation init sequence. + * + * Return: 0 if OK + */ +int noncached_init(void); + +phys_addr_t noncached_alloc(size_t size, size_t align); +#endif /* CONFIG_SYS_NONCACHED_MEMORY */ + #endif /* _ASM_SYSTEM_H */ diff --git a/arch/mips/lib/cache.c b/arch/mips/lib/cache.c index ec652f0fba8..d23b38d6b93 100644 --- a/arch/mips/lib/cache.c +++ b/arch/mips/lib/cache.c @@ -6,6 +6,7 @@ #include <common.h> #include <cpu_func.h> +#include <malloc.h> #include <asm/cache.h> #include <asm/cacheops.h> #include <asm/cm.h> @@ -197,3 +198,45 @@ void dcache_disable(void) /* ensure the pipeline doesn't contain now-invalid instructions */ instruction_hazard_barrier(); } + +#ifdef CONFIG_SYS_NONCACHED_MEMORY +static unsigned long noncached_start; +static unsigned long noncached_end; +static unsigned long noncached_next; + +void noncached_set_region(void) +{ +} + +int noncached_init(void) +{ + phys_addr_t start, end; + size_t size; + + /* If this calculation changes, update board_f.c:reserve_noncached() */ + end = ALIGN(mem_malloc_start, MMU_SECTION_SIZE) - MMU_SECTION_SIZE; + size = ALIGN(CONFIG_SYS_NONCACHED_MEMORY, MMU_SECTION_SIZE); + start = end - size; + + debug("mapping memory %pa-%pa non-cached\n", &start, &end); + + noncached_start = start; + noncached_end = end; + noncached_next = start; + + return 0; +} + +phys_addr_t noncached_alloc(size_t size, size_t align) +{ + phys_addr_t next = ALIGN(noncached_next, align); + + if (next >= noncached_end || (noncached_end - next) < size) + return 0; + + debug("allocated %zu bytes of uncached memory @%pa\n", size, &next); + noncached_next = next + size; + + return CKSEG1ADDR(next); +} +#endif /* CONFIG_SYS_NONCACHED_MEMORY */ 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..008a28f991c --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/Kconfig @@ -0,0 +1,115 @@ + +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" + +config BOARD_MT7621_RFB + bool "MediaTek MT7621 RFB (SPI-NOR)" + help + The reference design of MT7621A (WS3010) booting from SPI-NOR flash. + The board can be configured with DDR2 (64MiB~256MiB) or DDR3 + (128MiB~512MiB). The board has 16 MiB SPI-NOR flash, built-in MT7530 + GbE switch, 1 UART, 1 USB 2.0 host, 1 USB 3.0 host, 1 SDXC, 3 PCIe + sockets, 1 RGMII to external GbE PHY, 2 audio jacks (in/out), + JTAG pins and expansion GPIO pins. + +config BOARD_MT7621_NAND_RFB + bool "MediaTek MT7621 RFB (NAND)" + help + The reference design of MT7621A (WS3010) booting from NAND flash. + The board can be configured with DDR2 (64MiB~256MiB) or DDR3 + (128MiB~512MiB). The board has 128 MiB parallel NAND flash, built-in + MT7530 GbE switch, 1 UART, 1 USB 2.0 host, 1 USB 3.0 host, 3 PCIe + sockets, 1 RGMII to external GbE PHY, 2 audio jacks (in/out), + JTAG pins and expansion GPIO pins. + +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 (;;) + ; +} diff --git a/board/mediatek/mt7621/MAINTAINERS b/board/mediatek/mt7621/MAINTAINERS new file mode 100644 index 00000000000..f83141cea1d --- /dev/null +++ b/board/mediatek/mt7621/MAINTAINERS @@ -0,0 +1,8 @@ +MT7621_RFB BOARD +M: Weijie Gao <weijie.gao@mediatek.com> +S: Maintained +F: board/mediatek/mt7621 +F: configs/mt7621_rfb_defconfig +F: configs/mt7621_nand_rfb_defconfig +F: arch/mips/dts/mediatek,mt7621-rfb.dts +F: arch/mips/dts/mediatek,mt7621-nand-rfb.dts diff --git a/board/mediatek/mt7621/Makefile b/board/mediatek/mt7621/Makefile new file mode 100644 index 00000000000..db129c5abae --- /dev/null +++ b/board/mediatek/mt7621/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += board.o diff --git a/board/mediatek/mt7621/board.c b/board/mediatek/mt7621/board.c new file mode 100644 index 00000000000..0496f3f8067 --- /dev/null +++ b/board/mediatek/mt7621/board.c @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 931619c366f..908d7d17fda 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -884,7 +884,7 @@ config SPL_NAND_SIMPLE expose the cmd_ctrl() interface. config SPL_NAND_BASE - depends on SPL_NAND_DRIVERS + depends on SPL_NAND_SUPPORT bool "Use Base NAND Driver" help Include nand_base.c in the SPL. diff --git a/common/spl/spl_legacy.c b/common/spl/spl_legacy.c index 2ec71544238..ae8731c782a 100644 --- a/common/spl/spl_legacy.c +++ b/common/spl/spl_legacy.c @@ -88,15 +88,29 @@ int spl_load_legacy_img(struct spl_image_info *spl_image, /* Read header into local struct */ load->read(load, header, sizeof(hdr), &hdr); + /* + * If the payload is compressed, the decompressed data should be + * directly write to its load address. + */ + if (spl_image_get_comp(&hdr) != IH_COMP_NONE) + spl_image->flags |= SPL_COPY_PAYLOAD_ONLY; + ret = spl_parse_image_header(spl_image, bootdev, &hdr); if (ret) return ret; - dataptr = header + sizeof(hdr); - /* Read image */ switch (spl_image_get_comp(&hdr)) { case IH_COMP_NONE: + dataptr = header; + + /* + * Image header will be skipped only if SPL_COPY_PAYLOAD_ONLY + * is set + */ + if (spl_image->flags & SPL_COPY_PAYLOAD_ONLY) + dataptr += sizeof(hdr); + load->read(load, dataptr, spl_image->size, (void *)(unsigned long)spl_image->load_addr); break; @@ -104,6 +118,9 @@ int spl_load_legacy_img(struct spl_image_info *spl_image, case IH_COMP_LZMA: lzma_len = LZMA_LEN; + /* dataptr points to compressed payload */ + dataptr = header + sizeof(hdr); + debug("LZMA: Decompressing %08lx to %08lx\n", dataptr, spl_image->load_addr); src = malloc(spl_image->size); diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c index 82a10ffa63a..7b7579a2df1 100644 --- a/common/spl/spl_nand.c +++ b/common/spl/spl_nand.c @@ -56,6 +56,21 @@ static ulong spl_nand_fit_read(struct spl_load_info *load, ulong offs, return size / load->bl_len; } +static ulong spl_nand_legacy_read(struct spl_load_info *load, ulong offs, + ulong size, void *dst) +{ + int err; + + debug("%s: offs %lx, size %lx, dst %p\n", + __func__, offs, size, dst); + + err = nand_spl_load_image(offs, size, dst); + if (err) + return 0; + + return size; +} + struct mtd_info * __weak nand_get_mtd(void) { return NULL; @@ -93,6 +108,18 @@ static int spl_nand_load_element(struct spl_image_info *spl_image, load.bl_len = bl_len; load.read = spl_nand_fit_read; return spl_load_imx_container(spl_image, &load, offset / bl_len); + } else if (IS_ENABLED(CONFIG_SPL_LEGACY_IMAGE_FORMAT) && + image_get_magic(header) == IH_MAGIC) { + struct spl_load_info load; + + debug("Found legacy image\n"); + load.dev = NULL; + load.priv = NULL; + load.filename = NULL; + load.bl_len = 1; + load.read = spl_nand_legacy_read; + + return spl_load_legacy_img(spl_image, bootdev, &load, offset); } else { err = spl_parse_image_header(spl_image, bootdev, header); if (err) diff --git a/configs/mt7621_nand_rfb_defconfig b/configs/mt7621_nand_rfb_defconfig new file mode 100644 index 00000000000..0ad4849eb2a --- /dev/null +++ b/configs/mt7621_nand_rfb_defconfig @@ -0,0 +1,89 @@ +CONFIG_MIPS=y +CONFIG_SYS_MALLOC_LEN=0x100000 +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y +CONFIG_NR_DRAM_BANKS=1 +CONFIG_ENV_SIZE=0x1000 +CONFIG_DEFAULT_DEVICE_TREE="mediatek,mt7621-nand-rfb" +CONFIG_SPL_SERIAL=y +CONFIG_SPL_SYS_MALLOC_F_LEN=0x100000 +CONFIG_SPL=y +CONFIG_DEBUG_UART_BASE=0xbe000c00 +CONFIG_DEBUG_UART_CLOCK=50000000 +CONFIG_SYS_LOAD_ADDR=0x83000000 +CONFIG_ARCH_MTMIPS=y +CONFIG_SOC_MT7621=y +CONFIG_MT7621_BOOT_FROM_NAND=y +CONFIG_BOARD_MT7621_NAND_RFB=y +# CONFIG_MIPS_CACHE_SETUP is not set +# CONFIG_MIPS_CACHE_DISABLE is not set +CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEBUG_UART=y +CONFIG_FIT=y +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_SPL_MAX_SIZE=0x30000 +CONFIG_SPL_BSS_START_ADDR=0x80140000 +CONFIG_SPL_BSS_MAX_SIZE=0x80000 +CONFIG_SPL_SYS_MALLOC_SIMPLE=y +CONFIG_SPL_NAND_SUPPORT=y +CONFIG_SPL_NAND_BASE=y +CONFIG_SPL_NAND_IDENT=y +# CONFIG_BOOTM_NETBSD is not set +# CONFIG_BOOTM_PLAN9 is not set +# CONFIG_BOOTM_RTEMS is not set +# CONFIG_BOOTM_VXWORKS is not set +CONFIG_SYS_BOOTM_LEN=0x2000000 +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_XIMG is not set +# CONFIG_CMD_CRC32 is not set +# CONFIG_CMD_DM is not set +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_GPIO=y +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_MTD=y +CONFIG_CMD_PART=y +# CONFIG_CMD_PINMUX is not set +CONFIG_CMD_USB=y +# CONFIG_CMD_NFS is not set +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +# CONFIG_SPL_DOS_PARTITION is not set +# CONFIG_ISO_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_PARTITION_TYPE_GUID=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_NET_RANDOM_ETHADDR=y +# CONFIG_I2C is not set +# CONFIG_INPUT is not set +CONFIG_MMC=y +# CONFIG_MMC_QUIRKS is not set +# CONFIG_MMC_HW_PARTITIONING is not set +CONFIG_MMC_MTK=y +CONFIG_MTD=y +CONFIG_DM_MTD=y +CONFIG_MTD_RAW_NAND=y +CONFIG_NAND_MT7621=y +CONFIG_SYS_NAND_ONFI_DETECTION=y +CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y +CONFIG_SYS_NAND_U_BOOT_OFFS=0x0 +CONFIG_MEDIATEK_ETH=y +CONFIG_PHY=y +CONFIG_PHY_MTK_TPHY=y +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_SYSRESET=y +CONFIG_SYSRESET_RESETCTL=y +CONFIG_USB=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_MTK=y +CONFIG_USB_STORAGE=y +CONFIG_WDT=y +CONFIG_WDT_MT7621=y +CONFIG_FAT_WRITE=y +# CONFIG_BINMAN_FDT is not set +CONFIG_LZMA=y +# CONFIG_GZIP is not set +CONFIG_SPL_LZMA=y diff --git a/configs/mt7621_rfb_defconfig b/configs/mt7621_rfb_defconfig new file mode 100644 index 00000000000..fa663648173 --- /dev/null +++ b/configs/mt7621_rfb_defconfig @@ -0,0 +1,86 @@ +CONFIG_MIPS=y +CONFIG_SYS_MALLOC_LEN=0x100000 +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y +CONFIG_NR_DRAM_BANKS=1 +CONFIG_ENV_SIZE=0x1000 +CONFIG_DEFAULT_DEVICE_TREE="mediatek,mt7621-rfb" +CONFIG_SPL_SERIAL=y +CONFIG_SPL_SYS_MALLOC_F_LEN=0x40000 +CONFIG_SPL=y +CONFIG_DEBUG_UART_BASE=0xbe000c00 +CONFIG_DEBUG_UART_CLOCK=50000000 +CONFIG_SYS_LOAD_ADDR=0x83000000 +CONFIG_ARCH_MTMIPS=y +CONFIG_SOC_MT7621=y +# CONFIG_MIPS_CACHE_SETUP is not set +# CONFIG_MIPS_CACHE_DISABLE is not set +CONFIG_RESTORE_EXCEPTION_VECTOR_BASE=y +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEBUG_UART=y +CONFIG_TPL_SYS_MALLOC_F_LEN=0x1000 +CONFIG_FIT=y +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_SPL_MAX_SIZE=0x30000 +CONFIG_SPL_BSS_START_ADDR=0x80140000 +CONFIG_SPL_BSS_MAX_SIZE=0x80000 +CONFIG_SPL_SYS_MALLOC_SIMPLE=y +CONFIG_SPL_NOR_SUPPORT=y +CONFIG_TPL=y +# CONFIG_TPL_FRAMEWORK is not set +# CONFIG_BOOTM_NETBSD is not set +# CONFIG_BOOTM_PLAN9 is not set +# CONFIG_BOOTM_RTEMS is not set +# CONFIG_BOOTM_VXWORKS is not set +CONFIG_SYS_BOOTM_LEN=0x2000000 +# CONFIG_CMD_ELF is not set +# CONFIG_CMD_XIMG is not set +# CONFIG_CMD_CRC32 is not set +# CONFIG_CMD_DM is not set +CONFIG_CMD_GPIO=y +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_MMC=y +CONFIG_CMD_PART=y +# CONFIG_CMD_PINMUX is not set +CONFIG_CMD_SPI=y +# CONFIG_CMD_NFS is not set +CONFIG_DOS_PARTITION=y +# CONFIG_SPL_DOS_PARTITION is not set +# CONFIG_ISO_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_PARTITION_TYPE_GUID=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_NET_RANDOM_ETHADDR=y +# CONFIG_I2C is not set +# CONFIG_INPUT is not set +CONFIG_MMC=y +# CONFIG_MMC_QUIRKS is not set +# CONFIG_MMC_HW_PARTITIONING is not set +CONFIG_MMC_MTK=y +CONFIG_SF_DEFAULT_SPEED=20000000 +CONFIG_SPI_FLASH_BAR=y +CONFIG_SPI_FLASH_EON=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_ISSI=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_XMC=y +CONFIG_SPI_FLASH_XTX=y +CONFIG_MEDIATEK_ETH=y +CONFIG_PHY=y +CONFIG_PHY_MTK_TPHY=y +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_SPI=y +CONFIG_MT7621_SPI=y +CONFIG_SYSRESET=y +CONFIG_SYSRESET_RESETCTL=y +CONFIG_WDT=y +CONFIG_WDT_MT7621=y +# CONFIG_BINMAN_FDT is not set +CONFIG_LZMA=y +# CONFIG_GZIP is not set +CONFIG_SPL_LZMA=y diff --git a/doc/board/index.rst b/doc/board/index.rst index f90a9cad457..01b99f9cf50 100644 --- a/doc/board/index.rst +++ b/doc/board/index.rst @@ -23,6 +23,7 @@ Board-specific doc highbank/index intel/index kontron/index + mediatek/index microchip/index nokia/index nxp/index diff --git a/doc/board/mediatek/index.rst b/doc/board/mediatek/index.rst new file mode 100644 index 00000000000..38cd8cb5b24 --- /dev/null +++ b/doc/board/mediatek/index.rst @@ -0,0 +1,9 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Mediatek +========= + +.. toctree:: + :maxdepth: 2 + + mt7621 diff --git a/doc/board/mediatek/mt7621.rst b/doc/board/mediatek/mt7621.rst new file mode 100644 index 00000000000..1662255546f --- /dev/null +++ b/doc/board/mediatek/mt7621.rst @@ -0,0 +1,48 @@ +.. SPDX-License-Identifier: GPL-2.0 + +mt7621_rfb/mt7621_nand_rfb +========================== + +U-Boot for the MediaTek MT7621 boards + +Quick Start +----------- + +- Get the DDR initialization binary blob +- Configure CPU and DDR parameters +- Build U-Boot + +Get the DDR initialization binary blob +-------------------------------------- + +Download one from: + - https://raw.githubusercontent.com/mtk-openwrt/mt7621-lowlevel-preloader/master/mt7621_stage_sram.bin + - https://raw.githubusercontent.com/mtk-openwrt/mt7621-lowlevel-preloader/master/mt7621_stage_sram_noprint.bin + +mt7621_stage_sram_noprint.bin has removed all output logs. To use this one, +download and rename it to mt7621_stage_sram.bin + +Put the binary blob to the u-boot build directory. + +Configure CPU and DDR parameters +-------------------------------- + +menuconfig > MIPS architecture > MediaTek MIPS platforms > CPU & DDR configuration + +Select the correct DDR timing parameters for your board. The size shown here +must match the DDR size of you board. + +The frequency of CPU and DDR can also be adjusted. + +Build U-Boot +------------ + +.. code-block:: bash + + $ export CROSS_COMPILE=mipsel-linux- + $ make O=build mt7621_rfb_defconfig # or mt7621_nand_rfb_defconfig + $ cp mt7621_stage_sram.bin ./build/mt7621_stage_sram.bin + $ # or cp mt7621_stage_sram_noprint.bin ./build/mt7621_stage_sram.bin + $ make O=build + +Burn the u-boot-mt7621.bin to the SPI-NOR or NAND flash. diff --git a/drivers/clk/mtmips/Makefile b/drivers/clk/mtmips/Makefile index 732e7f25453..ee8b5afe879 100644 --- a/drivers/clk/mtmips/Makefile +++ b/drivers/clk/mtmips/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_SOC_MT7620) += clk-mt7620.o +obj-$(CONFIG_SOC_MT7621) += clk-mt7621.o obj-$(CONFIG_SOC_MT7628) += clk-mt7628.o diff --git a/drivers/clk/mtmips/clk-mt7621.c b/drivers/clk/mtmips/clk-mt7621.c new file mode 100644 index 00000000000..03363b70d74 --- /dev/null +++ b/drivers/clk/mtmips/clk-mt7621.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <regmap.h> +#include <syscon.h> +#include <dt-bindings/clock/mt7621-clk.h> +#include <linux/io.h> +#include <linux/bitops.h> +#include <linux/bitfield.h> + +#define SYSC_MAP_SIZE 0x100 +#define MEMC_MAP_SIZE 0x1000 + +/* SYSC */ +#define SYSCFG0_REG 0x10 +#define XTAL_MODE_SEL GENMASK(8, 6) + +#define CLKCFG0_REG 0x2c +#define CPU_CLK_SEL GENMASK(31, 30) +#define PERI_CLK_SEL BIT(4) + +#define CLKCFG1_REG 0x30 + +#define CUR_CLK_STS_REG 0x44 +#define CUR_CPU_FDIV GENMASK(12, 8) +#define CUR_CPU_FFRAC GENMASK(4, 0) + +/* MEMC */ +#define MEMPLL1_REG 0x0604 +#define RG_MEPL_DIV2_SEL GENMASK(2, 1) + +#define MEMPLL6_REG 0x0618 +#define MEMPLL18_REG 0x0648 +#define RG_MEPL_PREDIV GENMASK(13, 12) +#define RG_MEPL_FBDIV GENMASK(10, 4) + +/* Fixed 500M clock */ +#define GMPLL_CLK 500000000 + +struct mt7621_clk_priv { + void __iomem *sysc_base; + int cpu_clk; + int ddr_clk; + int sys_clk; + int xtal_clk; +}; + +enum mt7621_clk_src { + CLK_SRC_CPU, + CLK_SRC_DDR, + CLK_SRC_SYS, + CLK_SRC_XTAL, + CLK_SRC_PERI, + CLK_SRC_125M, + CLK_SRC_150M, + CLK_SRC_250M, + CLK_SRC_270M, + + __CLK_SRC_MAX +}; + +struct mt7621_clk_map { + u32 cgbit; + enum mt7621_clk_src clksrc; +}; + +#define CLK_MAP(_id, _cg, _src) \ + [_id] = { .cgbit = (_cg), .clksrc = (_src) } + +#define CLK_MAP_SRC(_id, _src) \ + [_id] = { .cgbit = UINT32_MAX, .clksrc = (_src) } + +static const struct mt7621_clk_map mt7621_clk_mappings[] = { + CLK_MAP_SRC(MT7621_CLK_XTAL, CLK_SRC_XTAL), + CLK_MAP_SRC(MT7621_CLK_CPU, CLK_SRC_CPU), + CLK_MAP_SRC(MT7621_CLK_BUS, CLK_SRC_SYS), + CLK_MAP_SRC(MT7621_CLK_50M, CLK_SRC_PERI), + CLK_MAP_SRC(MT7621_CLK_125M, CLK_SRC_125M), + CLK_MAP_SRC(MT7621_CLK_150M, CLK_SRC_150M), + CLK_MAP_SRC(MT7621_CLK_250M, CLK_SRC_250M), + CLK_MAP_SRC(MT7621_CLK_270M, CLK_SRC_270M), + + CLK_MAP(MT7621_CLK_HSDMA, 5, CLK_SRC_150M), + CLK_MAP(MT7621_CLK_FE, 6, CLK_SRC_250M), + CLK_MAP(MT7621_CLK_SP_DIVTX, 7, CLK_SRC_270M), + CLK_MAP(MT7621_CLK_TIMER, 8, CLK_SRC_PERI), + CLK_MAP(MT7621_CLK_PCM, 11, CLK_SRC_270M), + CLK_MAP(MT7621_CLK_PIO, 13, CLK_SRC_PERI), + CLK_MAP(MT7621_CLK_GDMA, 14, CLK_SRC_SYS), + CLK_MAP(MT7621_CLK_NAND, 15, CLK_SRC_125M), + CLK_MAP(MT7621_CLK_I2C, 16, CLK_SRC_PERI), + CLK_MAP(MT7621_CLK_I2S, 17, CLK_SRC_270M), + CLK_MAP(MT7621_CLK_SPI, 18, CLK_SRC_SYS), + CLK_MAP(MT7621_CLK_UART1, 19, CLK_SRC_PERI), + CLK_MAP(MT7621_CLK_UART2, 20, CLK_SRC_PERI), + CLK_MAP(MT7621_CLK_UART3, 21, CLK_SRC_PERI), + CLK_MAP(MT7621_CLK_ETH, 23, CLK_SRC_PERI), + CLK_MAP(MT7621_CLK_PCIE0, 24, CLK_SRC_125M), + CLK_MAP(MT7621_CLK_PCIE1, 25, CLK_SRC_125M), + CLK_MAP(MT7621_CLK_PCIE2, 26, CLK_SRC_125M), + CLK_MAP(MT7621_CLK_CRYPTO, 29, CLK_SRC_250M), + CLK_MAP(MT7621_CLK_SHXC, 30, CLK_SRC_PERI), + + CLK_MAP_SRC(MT7621_CLK_MAX, __CLK_SRC_MAX), + + CLK_MAP_SRC(MT7621_CLK_DDR, CLK_SRC_DDR), +}; + +static ulong mt7621_clk_get_rate(struct clk *clk) +{ + struct mt7621_clk_priv *priv = dev_get_priv(clk->dev); + u32 val; + + switch (mt7621_clk_mappings[clk->id].clksrc) { + case CLK_SRC_CPU: + return priv->cpu_clk; + case CLK_SRC_DDR: + return priv->ddr_clk; + case CLK_SRC_SYS: + return priv->sys_clk; + case CLK_SRC_XTAL: + return priv->xtal_clk; + case CLK_SRC_PERI: + val = readl(priv->sysc_base + CLKCFG0_REG); + if (val & PERI_CLK_SEL) + return priv->xtal_clk; + else + return GMPLL_CLK / 10; + case CLK_SRC_125M: + return 125000000; + case CLK_SRC_150M: + return 150000000; + case CLK_SRC_250M: + return 250000000; + case CLK_SRC_270M: + return 270000000; + default: + return 0; + } +} + +static int mt7621_clk_enable(struct clk *clk) +{ + struct mt7621_clk_priv *priv = dev_get_priv(clk->dev); + u32 cgbit; + + cgbit = mt7621_clk_mappings[clk->id].cgbit; + if (cgbit == UINT32_MAX) + return -ENOSYS; + + setbits_32(priv->sysc_base + CLKCFG1_REG, BIT(cgbit)); + + return 0; +} + +static int mt7621_clk_disable(struct clk *clk) +{ + struct mt7621_clk_priv *priv = dev_get_priv(clk->dev); + u32 cgbit; + + cgbit = mt7621_clk_mappings[clk->id].cgbit; + if (cgbit == UINT32_MAX) + return -ENOSYS; + + clrbits_32(priv->sysc_base + CLKCFG1_REG, BIT(cgbit)); + + return 0; +} + +static int mt7621_clk_request(struct clk *clk) +{ + if (clk->id >= ARRAY_SIZE(mt7621_clk_mappings)) + return -EINVAL; + return 0; +} + +const struct clk_ops mt7621_clk_ops = { + .request = mt7621_clk_request, + .enable = mt7621_clk_enable, + .disable = mt7621_clk_disable, + .get_rate = mt7621_clk_get_rate, +}; + +static void mt7621_get_clocks(struct mt7621_clk_priv *priv, struct regmap *memc) +{ + u32 bs, xtal_sel, clkcfg0, cur_clk, mempll, dividx, fb; + u32 xtal_clk, xtal_div, ffiv, ffrac, cpu_clk, ddr_clk; + static const u32 xtal_div_tbl[] = {0, 1, 2, 2}; + + bs = readl(priv->sysc_base + SYSCFG0_REG); + clkcfg0 = readl(priv->sysc_base + CLKCFG0_REG); + cur_clk = readl(priv->sysc_base + CUR_CLK_STS_REG); + + xtal_sel = FIELD_GET(XTAL_MODE_SEL, bs); + + if (xtal_sel <= 2) + xtal_clk = 20 * 1000 * 1000; + else if (xtal_sel <= 5) + xtal_clk = 40 * 1000 * 1000; + else + xtal_clk = 25 * 1000 * 1000; + + switch (FIELD_GET(CPU_CLK_SEL, clkcfg0)) { + case 0: + cpu_clk = GMPLL_CLK; + break; + case 1: + regmap_read(memc, MEMPLL18_REG, &mempll); + dividx = FIELD_GET(RG_MEPL_PREDIV, mempll); + fb = FIELD_GET(RG_MEPL_FBDIV, mempll); + xtal_div = 1 << xtal_div_tbl[dividx]; + cpu_clk = (fb + 1) * xtal_clk / xtal_div; + break; + default: + cpu_clk = xtal_clk; + } + + ffiv = FIELD_GET(CUR_CPU_FDIV, cur_clk); + ffrac = FIELD_GET(CUR_CPU_FFRAC, cur_clk); + cpu_clk = cpu_clk / ffiv * ffrac; + + regmap_read(memc, MEMPLL6_REG, &mempll); + dividx = FIELD_GET(RG_MEPL_PREDIV, mempll); + fb = FIELD_GET(RG_MEPL_FBDIV, mempll); + xtal_div = 1 << xtal_div_tbl[dividx]; + ddr_clk = fb * xtal_clk / xtal_div; + + regmap_read(memc, MEMPLL1_REG, &bs); + if (!FIELD_GET(RG_MEPL_DIV2_SEL, bs)) + ddr_clk *= 2; + + priv->cpu_clk = cpu_clk; + priv->sys_clk = cpu_clk / 4; + priv->ddr_clk = ddr_clk; + priv->xtal_clk = xtal_clk; +} + +static int mt7621_clk_probe(struct udevice *dev) +{ + struct mt7621_clk_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args args; + struct udevice *pdev; + struct regmap *memc; + int ret; + + pdev = dev_get_parent(dev); + if (!pdev) + return -ENODEV; + + priv->sysc_base = dev_remap_addr(pdev); + if (!priv->sysc_base) + return -EINVAL; + + /* get corresponding memc phandle */ + ret = dev_read_phandle_with_args(dev, "mediatek,memc", NULL, 0, 0, + &args); + if (ret) + return ret; + + memc = syscon_node_to_regmap(args.node); + if (IS_ERR(memc)) + return PTR_ERR(memc); + + mt7621_get_clocks(priv, memc); + + return 0; +} + +static const struct udevice_id mt7621_clk_ids[] = { + { .compatible = "mediatek,mt7621-clk" }, + { } +}; + +U_BOOT_DRIVER(mt7621_clk) = { + .name = "mt7621-clk", + .id = UCLASS_CLK, + .of_match = mt7621_clk_ids, + .probe = mt7621_clk_probe, + .priv_auto = sizeof(struct mt7621_clk_priv), + .ops = &mt7621_clk_ops, +}; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3c73a7f6183..aaa152fae73 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -553,7 +553,7 @@ config MT7620_GPIO config MT7621_GPIO bool "MediaTek MT7621 GPIO driver" - depends on DM_GPIO && SOC_MT7628 + depends on DM_GPIO && (SOC_MT7621 || SOC_MT7628) default y help Say yes here to support MediaTek MT7621 compatible GPIOs. diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c index 97182ffd7f5..e61e8cf4b94 100644 --- a/drivers/mmc/mtk-sd.c +++ b/drivers/mmc/mtk-sd.c @@ -1761,6 +1761,18 @@ static const struct msdc_compatible mt7620_compat = { .default_pad_dly = true, }; +static const struct msdc_compatible mt7621_compat = { + .clk_div_bits = 8, + .pad_tune0 = false, + .async_fifo = true, + .data_tune = true, + .busy_check = false, + .stop_clk_fix = false, + .enhance_rx = false, + .builtin_pad_ctrl = true, + .default_pad_dly = true, +}; + static const struct msdc_compatible mt7622_compat = { .clk_div_bits = 12, .pad_tune0 = true, @@ -1809,6 +1821,7 @@ static const struct msdc_compatible mt8183_compat = { static const struct udevice_id msdc_ids[] = { { .compatible = "mediatek,mt7620-mmc", .data = (ulong)&mt7620_compat }, + { .compatible = "mediatek,mt7621-mmc", .data = (ulong)&mt7621_compat }, { .compatible = "mediatek,mt7622-mmc", .data = (ulong)&mt7622_compat }, { .compatible = "mediatek,mt7623-mmc", .data = (ulong)&mt7623_compat }, { .compatible = "mediatek,mt8512-mmc", .data = (ulong)&mt8512_compat }, diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 190300fc179..ce67d1abde2 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -526,12 +526,25 @@ config TEGRA_NAND help Enables support for NAND Flash chips on Tegra SoCs platforms. +config NAND_MT7621 + bool "Support for MediaTek MT7621 NAND flash controller" + depends on SOC_MT7621 + select SYS_NAND_SELF_INIT + select SPL_SYS_NAND_SELF_INIT + imply CMD_NAND + help + This enables NAND driver for the NAND flash controller on MediaTek + MT7621 platform. + The controller supports 4~12 bits correction per 512 bytes with a + maximum 4KB page size. + comment "Generic NAND options" config SYS_NAND_BLOCK_SIZE hex "NAND chip eraseblock size" depends on ARCH_SUNXI || SPL_NAND_SUPPORT || TPL_NAND_SUPPORT - depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_FSL_IFC + depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && \ + !NAND_FSL_IFC && !NAND_MT7621 help Number of data bytes in one eraseblock for the NAND chip on the board. This is the multiple of NAND_PAGE_SIZE and the number of @@ -556,7 +569,7 @@ config SYS_NAND_PAGE_SIZE depends on ARCH_SUNXI || NAND_OMAP_GPMC || NAND_LPC32XX_SLC || \ SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \ (NAND_ATMEL && SPL_NAND_SUPPORT) || SPL_GENERATE_ATMEL_PMECC_HEADER - depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC + depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_MT7621 help Number of data bytes in one page for the NAND chip on the board, not including the OOB area. diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index e3f6b903f75..f278f31f5cd 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o obj-$(CONFIG_NAND_STM32_FMC2) += stm32_fmc2_nand.o obj-$(CONFIG_CORTINA_NAND) += cortina_nand.o obj-$(CONFIG_ROCKCHIP_NAND) += rockchip_nfc.o +obj-$(CONFIG_NAND_MT7621) += mt7621_nand.o else # minimal SPL drivers @@ -80,5 +81,6 @@ obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o obj-$(CONFIG_NAND_MXS) += mxs_nand_spl.o mxs_nand.o obj-$(CONFIG_NAND_SUNXI) += sunxi_nand_spl.o +obj-$(CONFIG_NAND_MT7621) += mt7621_nand_spl.o mt7621_nand.o endif # drivers diff --git a/drivers/mtd/nand/raw/mt7621_nand.c b/drivers/mtd/nand/raw/mt7621_nand.c new file mode 100644 index 00000000000..2fd89349392 --- /dev/null +++ b/drivers/mtd/nand/raw/mt7621_nand.c @@ -0,0 +1,1205 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <log.h> +#include <nand.h> +#include <malloc.h> +#include <asm/addrspace.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/sizes.h> +#include <linux/bitops.h> +#include <linux/bitfield.h> +#include "mt7621_nand.h" + +/* NFI core registers */ +#define NFI_CNFG 0x000 +#define CNFG_OP_MODE GENMASK(14, 12) +#define CNFG_OP_CUSTOM 6 +#define CNFG_AUTO_FMT_EN BIT(9) +#define CNFG_HW_ECC_EN BIT(8) +#define CNFG_BYTE_RW BIT(6) +#define CNFG_READ_MODE BIT(1) + +#define NFI_PAGEFMT 0x004 +#define PAGEFMT_FDM_ECC GENMASK(15, 12) +#define PAGEFMT_FDM GENMASK(11, 8) +#define PAGEFMT_SPARE GENMASK(5, 4) +#define PAGEFMT_PAGE GENMASK(1, 0) + +#define NFI_CON 0x008 +#define CON_NFI_SEC GENMASK(15, 12) +#define CON_NFI_BWR BIT(9) +#define CON_NFI_BRD BIT(8) +#define CON_NFI_RST BIT(1) +#define CON_FIFO_FLUSH BIT(0) + +#define NFI_ACCCON 0x00c +#define ACCCON_POECS GENMASK(31, 28) +#define ACCCON_POECS_DEF 3 +#define ACCCON_PRECS GENMASK(27, 22) +#define ACCCON_PRECS_DEF 3 +#define ACCCON_C2R GENMASK(21, 16) +#define ACCCON_C2R_DEF 7 +#define ACCCON_W2R GENMASK(15, 12) +#define ACCCON_W2R_DEF 7 +#define ACCCON_WH GENMASK(11, 8) +#define ACCCON_WH_DEF 15 +#define ACCCON_WST GENMASK(7, 4) +#define ACCCON_WST_DEF 15 +#define ACCCON_WST_MIN 3 +#define ACCCON_RLT GENMASK(3, 0) +#define ACCCON_RLT_DEF 15 +#define ACCCON_RLT_MIN 3 + +#define NFI_CMD 0x020 + +#define NFI_ADDRNOB 0x030 +#define ADDR_ROW_NOB GENMASK(6, 4) +#define ADDR_COL_NOB GENMASK(2, 0) + +#define NFI_COLADDR 0x034 +#define NFI_ROWADDR 0x038 + +#define NFI_STRDATA 0x040 +#define STR_DATA BIT(0) + +#define NFI_CNRNB 0x044 +#define CB2R_TIME GENMASK(7, 4) +#define STR_CNRNB BIT(0) + +#define NFI_DATAW 0x050 +#define NFI_DATAR 0x054 + +#define NFI_PIO_DIRDY 0x058 +#define PIO_DIRDY BIT(0) + +#define NFI_STA 0x060 +#define STA_NFI_FSM GENMASK(19, 16) +#define STA_FSM_CUSTOM_DATA 14 +#define STA_BUSY BIT(8) +#define STA_ADDR BIT(1) +#define STA_CMD BIT(0) + +#define NFI_ADDRCNTR 0x070 +#define SEC_CNTR GENMASK(15, 12) +#define SEC_ADDR GENMASK(9, 0) + +#define NFI_CSEL 0x090 +#define CSEL GENMASK(1, 0) + +#define NFI_FDM0L 0x0a0 +#define NFI_FDML(n) (0x0a0 + ((n) << 3)) + +#define NFI_FDM0M 0x0a4 +#define NFI_FDMM(n) (0x0a4 + ((n) << 3)) + +#define NFI_MASTER_STA 0x210 +#define MAS_ADDR GENMASK(11, 9) +#define MAS_RD GENMASK(8, 6) +#define MAS_WR GENMASK(5, 3) +#define MAS_RDDLY GENMASK(2, 0) + +/* ECC engine registers */ +#define ECC_ENCCON 0x000 +#define ENC_EN BIT(0) + +#define ECC_ENCCNFG 0x004 +#define ENC_CNFG_MSG GENMASK(28, 16) +#define ENC_MODE GENMASK(5, 4) +#define ENC_MODE_NFI 1 +#define ENC_TNUM GENMASK(2, 0) + +#define ECC_ENCIDLE 0x00c +#define ENC_IDLE BIT(0) + +#define ECC_DECCON 0x100 +#define DEC_EN BIT(0) + +#define ECC_DECCNFG 0x104 +#define DEC_EMPTY_EN BIT(31) +#define DEC_CS GENMASK(28, 16) +#define DEC_CON GENMASK(13, 12) +#define DEC_CON_EL 2 +#define DEC_MODE GENMASK(5, 4) +#define DEC_MODE_NFI 1 +#define DEC_TNUM GENMASK(2, 0) + +#define ECC_DECIDLE 0x10c +#define DEC_IDLE BIT(1) + +#define ECC_DECENUM 0x114 +#define ERRNUM_S 2 +#define ERRNUM_M GENMASK(3, 0) + +#define ECC_DECDONE 0x118 +#define DEC_DONE7 BIT(7) +#define DEC_DONE6 BIT(6) +#define DEC_DONE5 BIT(5) +#define DEC_DONE4 BIT(4) +#define DEC_DONE3 BIT(3) +#define DEC_DONE2 BIT(2) +#define DEC_DONE1 BIT(1) +#define DEC_DONE0 BIT(0) + +#define ECC_DECEL(n) (0x11c + (n) * 4) +#define DEC_EL_ODD_S 16 +#define DEC_EL_M 0x1fff +#define DEC_EL_BYTE_POS_S 3 +#define DEC_EL_BIT_POS_M GENMASK(2, 0) + +#define ECC_FDMADDR 0x13c + +/* ENCIDLE and DECIDLE */ +#define ECC_IDLE BIT(0) + +#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \ + (FIELD_PREP(ACCCON_POECS, tpoecs) | \ + FIELD_PREP(ACCCON_PRECS, tprecs) | \ + FIELD_PREP(ACCCON_C2R, tc2r) | \ + FIELD_PREP(ACCCON_W2R, tw2r) | \ + FIELD_PREP(ACCCON_WH, twh) | \ + FIELD_PREP(ACCCON_WST, twst) | \ + FIELD_PREP(ACCCON_RLT, trlt)) + +#define MASTER_STA_MASK (MAS_ADDR | MAS_RD | MAS_WR | \ + MAS_RDDLY) +#define NFI_RESET_TIMEOUT 1000000 +#define NFI_CORE_TIMEOUT 500000 +#define ECC_ENGINE_TIMEOUT 500000 + +#define ECC_SECTOR_SIZE 512 +#define ECC_PARITY_BITS 13 + +#define NFI_FDM_SIZE 8 + +/* Register base */ +#define NFI_BASE 0x1e003000 +#define NFI_ECC_BASE 0x1e003800 + +static struct mt7621_nfc nfc_dev; + +static const u16 mt7621_nfi_page_size[] = { SZ_512, SZ_2K, SZ_4K }; +static const u8 mt7621_nfi_spare_size[] = { 16, 26, 27, 28 }; +static const u8 mt7621_ecc_strength[] = { 4, 6, 8, 10, 12 }; + +static inline u32 nfi_read32(struct mt7621_nfc *nfc, u32 reg) +{ + return readl(nfc->nfi_regs + reg); +} + +static inline void nfi_write32(struct mt7621_nfc *nfc, u32 reg, u32 val) +{ + writel(val, nfc->nfi_regs + reg); +} + +static inline u16 nfi_read16(struct mt7621_nfc *nfc, u32 reg) +{ + return readw(nfc->nfi_regs + reg); +} + +static inline void nfi_write16(struct mt7621_nfc *nfc, u32 reg, u16 val) +{ + writew(val, nfc->nfi_regs + reg); +} + +static inline void ecc_write16(struct mt7621_nfc *nfc, u32 reg, u16 val) +{ + writew(val, nfc->ecc_regs + reg); +} + +static inline u32 ecc_read32(struct mt7621_nfc *nfc, u32 reg) +{ + return readl(nfc->ecc_regs + reg); +} + +static inline void ecc_write32(struct mt7621_nfc *nfc, u32 reg, u32 val) +{ + return writel(val, nfc->ecc_regs + reg); +} + +static inline u8 *oob_fdm_ptr(struct nand_chip *nand, int sect) +{ + return nand->oob_poi + sect * NFI_FDM_SIZE; +} + +static inline u8 *oob_ecc_ptr(struct mt7621_nfc *nfc, int sect) +{ + struct nand_chip *nand = &nfc->nand; + + return nand->oob_poi + nand->ecc.steps * NFI_FDM_SIZE + + sect * (nfc->spare_per_sector - NFI_FDM_SIZE); +} + +static inline u8 *page_data_ptr(struct nand_chip *nand, const u8 *buf, + int sect) +{ + return (u8 *)buf + sect * nand->ecc.size; +} + +static int mt7621_ecc_wait_idle(struct mt7621_nfc *nfc, u32 reg) +{ + u32 val; + int ret; + + ret = readw_poll_timeout(nfc->ecc_regs + reg, val, val & ECC_IDLE, + ECC_ENGINE_TIMEOUT); + if (ret) { + pr_warn("ECC engine timed out entering idle mode\n"); + return -EIO; + } + + return 0; +} + +static int mt7621_ecc_decoder_wait_done(struct mt7621_nfc *nfc, u32 sect) +{ + u32 val; + int ret; + + ret = readw_poll_timeout(nfc->ecc_regs + ECC_DECDONE, val, + val & (1 << sect), ECC_ENGINE_TIMEOUT); + if (ret) { + pr_warn("ECC decoder for sector %d timed out\n", sect); + return -ETIMEDOUT; + } + + return 0; +} + +static void mt7621_ecc_encoder_op(struct mt7621_nfc *nfc, bool enable) +{ + mt7621_ecc_wait_idle(nfc, ECC_ENCIDLE); + ecc_write16(nfc, ECC_ENCCON, enable ? ENC_EN : 0); +} + +static void mt7621_ecc_decoder_op(struct mt7621_nfc *nfc, bool enable) +{ + mt7621_ecc_wait_idle(nfc, ECC_DECIDLE); + ecc_write16(nfc, ECC_DECCON, enable ? DEC_EN : 0); +} + +static int mt7621_ecc_correct_check(struct mt7621_nfc *nfc, u8 *sector_buf, + u8 *fdm_buf, u32 sect) +{ + struct nand_chip *nand = &nfc->nand; + u32 decnum, num_error_bits, fdm_end_bits; + u32 error_locations, error_bit_loc; + u32 error_byte_pos, error_bit_pos; + int bitflips = 0; + u32 i; + + decnum = ecc_read32(nfc, ECC_DECENUM); + num_error_bits = (decnum >> (sect << ERRNUM_S)) & ERRNUM_M; + fdm_end_bits = (nand->ecc.size + NFI_FDM_SIZE) << 3; + + if (!num_error_bits) + return 0; + + if (num_error_bits == ERRNUM_M) + return -1; + + for (i = 0; i < num_error_bits; i++) { + error_locations = ecc_read32(nfc, ECC_DECEL(i / 2)); + error_bit_loc = (error_locations >> ((i % 2) * DEC_EL_ODD_S)) & + DEC_EL_M; + error_byte_pos = error_bit_loc >> DEC_EL_BYTE_POS_S; + error_bit_pos = error_bit_loc & DEC_EL_BIT_POS_M; + + if (error_bit_loc < (nand->ecc.size << 3)) { + if (sector_buf) { + sector_buf[error_byte_pos] ^= + (1 << error_bit_pos); + } + } else if (error_bit_loc < fdm_end_bits) { + if (fdm_buf) { + fdm_buf[error_byte_pos - nand->ecc.size] ^= + (1 << error_bit_pos); + } + } + + bitflips++; + } + + return bitflips; +} + +static int mt7621_nfc_wait_write_completion(struct mt7621_nfc *nfc, + struct nand_chip *nand) +{ + u16 val; + int ret; + + ret = readw_poll_timeout(nfc->nfi_regs + NFI_ADDRCNTR, val, + FIELD_GET(SEC_CNTR, val) >= nand->ecc.steps, + NFI_CORE_TIMEOUT); + + if (ret) { + pr_warn("NFI core write operation timed out\n"); + return -ETIMEDOUT; + } + + return ret; +} + +static void mt7621_nfc_hw_reset(struct mt7621_nfc *nfc) +{ + u32 val; + int ret; + + /* reset all registers and force the NFI master to terminate */ + nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST); + + /* wait for the master to finish the last transaction */ + ret = readw_poll_timeout(nfc->nfi_regs + NFI_MASTER_STA, val, + !(val & MASTER_STA_MASK), NFI_RESET_TIMEOUT); + if (ret) { + pr_warn("Failed to reset NFI master in %dms\n", + NFI_RESET_TIMEOUT); + } + + /* ensure any status register affected by the NFI master is reset */ + nfi_write16(nfc, NFI_CON, CON_FIFO_FLUSH | CON_NFI_RST); + nfi_write16(nfc, NFI_STRDATA, 0); +} + +static inline void mt7621_nfc_hw_init(struct mt7621_nfc *nfc) +{ + u32 acccon; + + /* + * CNRNB: nand ready/busy register + * ------------------------------- + * 7:4: timeout register for polling the NAND busy/ready signal + * 0 : poll the status of the busy/ready signal after [7:4]*16 cycles. + */ + nfi_write16(nfc, NFI_CNRNB, CB2R_TIME | STR_CNRNB); + + mt7621_nfc_hw_reset(nfc); + + /* Apply default access timing */ + acccon = ACCTIMING(ACCCON_POECS_DEF, ACCCON_PRECS_DEF, ACCCON_C2R_DEF, + ACCCON_W2R_DEF, ACCCON_WH_DEF, ACCCON_WST_DEF, + ACCCON_RLT_DEF); + + nfi_write32(nfc, NFI_ACCCON, acccon); +} + +static int mt7621_nfc_send_command(struct mt7621_nfc *nfc, u8 command) +{ + u32 val; + int ret; + + nfi_write32(nfc, NFI_CMD, command); + + ret = readl_poll_timeout(nfc->nfi_regs + NFI_STA, val, !(val & STA_CMD), + NFI_CORE_TIMEOUT); + if (ret) { + pr_warn("NFI core timed out entering command mode\n"); + return -EIO; + } + + return 0; +} + +static int mt7621_nfc_send_address_byte(struct mt7621_nfc *nfc, int addr) +{ + u32 val; + int ret; + + nfi_write32(nfc, NFI_COLADDR, addr); + nfi_write32(nfc, NFI_ROWADDR, 0); + nfi_write16(nfc, NFI_ADDRNOB, 1); + + ret = readl_poll_timeout(nfc->nfi_regs + NFI_STA, val, + !(val & STA_ADDR), NFI_CORE_TIMEOUT); + if (ret) { + pr_warn("NFI core timed out entering address mode\n"); + return -EIO; + } + + return 0; +} + +static void mt7621_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, + unsigned int ctrl) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + + if (ctrl & NAND_ALE) { + mt7621_nfc_send_address_byte(nfc, dat & 0xff); + } else if (ctrl & NAND_CLE) { + mt7621_nfc_hw_reset(nfc); + nfi_write16(nfc, NFI_CNFG, + FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM)); + mt7621_nfc_send_command(nfc, dat); + } +} + +static int mt7621_nfc_dev_ready(struct mtd_info *mtd) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + + if (nfi_read32(nfc, NFI_STA) & STA_BUSY) + return 0; + + return 1; +} + +static void mt7621_nfc_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + + nfi_write16(nfc, NFI_CSEL, 0); +} + +static void mt7621_nfc_wait_pio_ready(struct mt7621_nfc *nfc) +{ + int ret; + u16 val; + + ret = readw_poll_timeout(nfc->nfi_regs + NFI_PIO_DIRDY, val, + val & PIO_DIRDY, NFI_CORE_TIMEOUT); + if (ret < 0) + pr_err("NFI core PIO mode not ready\n"); +} + +static u32 mt7621_nfc_pio_read(struct mt7621_nfc *nfc, bool br) +{ + u32 reg, fsm; + + /* after each byte read, the NFI_STA reg is reset by the hardware */ + reg = nfi_read32(nfc, NFI_STA); + fsm = FIELD_GET(STA_NFI_FSM, reg); + + if (fsm != STA_FSM_CUSTOM_DATA) { + reg = nfi_read16(nfc, NFI_CNFG); + reg |= CNFG_READ_MODE | CNFG_BYTE_RW; + if (!br) + reg &= ~CNFG_BYTE_RW; + nfi_write16(nfc, NFI_CNFG, reg); + + /* + * set to max sector to allow the HW to continue reading over + * unaligned accesses + */ + nfi_write16(nfc, NFI_CON, CON_NFI_SEC | CON_NFI_BRD); + + /* trigger to fetch data */ + nfi_write16(nfc, NFI_STRDATA, STR_DATA); + } + + mt7621_nfc_wait_pio_ready(nfc); + + return nfi_read32(nfc, NFI_DATAR); +} + +static void mt7621_nfc_read_data(struct mt7621_nfc *nfc, u8 *buf, u32 len) +{ + while (((uintptr_t)buf & 3) && len) { + *buf = mt7621_nfc_pio_read(nfc, true); + buf++; + len--; + } + + while (len >= 4) { + *(u32 *)buf = mt7621_nfc_pio_read(nfc, false); + buf += 4; + len -= 4; + } + + while (len) { + *buf = mt7621_nfc_pio_read(nfc, true); + buf++; + len--; + } +} + +static void mt7621_nfc_read_data_discard(struct mt7621_nfc *nfc, u32 len) +{ + while (len >= 4) { + mt7621_nfc_pio_read(nfc, false); + len -= 4; + } + + while (len) { + mt7621_nfc_pio_read(nfc, true); + len--; + } +} + +static void mt7621_nfc_pio_write(struct mt7621_nfc *nfc, u32 val, bool bw) +{ + u32 reg, fsm; + + reg = nfi_read32(nfc, NFI_STA); + fsm = FIELD_GET(STA_NFI_FSM, reg); + + if (fsm != STA_FSM_CUSTOM_DATA) { + reg = nfi_read16(nfc, NFI_CNFG); + reg &= ~(CNFG_READ_MODE | CNFG_BYTE_RW); + if (bw) + reg |= CNFG_BYTE_RW; + nfi_write16(nfc, NFI_CNFG, reg); + + nfi_write16(nfc, NFI_CON, CON_NFI_SEC | CON_NFI_BWR); + nfi_write16(nfc, NFI_STRDATA, STR_DATA); + } + + mt7621_nfc_wait_pio_ready(nfc); + nfi_write32(nfc, NFI_DATAW, val); +} + +static void mt7621_nfc_write_data(struct mt7621_nfc *nfc, const u8 *buf, + u32 len) +{ + while (((uintptr_t)buf & 3) && len) { + mt7621_nfc_pio_write(nfc, *buf, true); + buf++; + len--; + } + + while (len >= 4) { + mt7621_nfc_pio_write(nfc, *(const u32 *)buf, false); + buf += 4; + len -= 4; + } + + while (len) { + mt7621_nfc_pio_write(nfc, *buf, true); + buf++; + len--; + } +} + +static void mt7621_nfc_write_data_empty(struct mt7621_nfc *nfc, u32 len) +{ + while (len >= 4) { + mt7621_nfc_pio_write(nfc, 0xffffffff, false); + len -= 4; + } + + while (len) { + mt7621_nfc_pio_write(nfc, 0xff, true); + len--; + } +} + +static void mt7621_nfc_write_byte(struct mtd_info *mtd, u8 byte) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + + mt7621_nfc_pio_write(nfc, byte, true); +} + +static void mt7621_nfc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + + return mt7621_nfc_write_data(nfc, buf, len); +} + +static u8 mt7621_nfc_read_byte(struct mtd_info *mtd) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + + return mt7621_nfc_pio_read(nfc, true); +} + +static void mt7621_nfc_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(mtd_to_nand(mtd)); + + mt7621_nfc_read_data(nfc, buf, len); +} + +static int mt7621_nfc_calc_ecc_strength(struct mt7621_nfc *nfc, + u32 avail_ecc_bytes) +{ + struct nand_chip *nand = &nfc->nand; + struct mtd_info *mtd = nand_to_mtd(nand); + u32 strength; + int i; + + strength = avail_ecc_bytes * 8 / ECC_PARITY_BITS; + + /* Find the closest supported ecc strength */ + for (i = ARRAY_SIZE(mt7621_ecc_strength) - 1; i >= 0; i--) { + if (mt7621_ecc_strength[i] <= strength) + break; + } + + if (unlikely(i < 0)) { + pr_err("OOB size (%u) is not supported\n", mtd->oobsize); + return -EINVAL; + } + + nand->ecc.strength = mt7621_ecc_strength[i]; + nand->ecc.bytes = DIV_ROUND_UP(nand->ecc.strength * ECC_PARITY_BITS, 8); + + pr_debug("ECC strength adjusted to %u bits\n", nand->ecc.strength); + + return i; +} + +static int mt7621_nfc_set_spare_per_sector(struct mt7621_nfc *nfc) +{ + struct nand_chip *nand = &nfc->nand; + struct mtd_info *mtd = nand_to_mtd(nand); + u32 size; + int i; + + size = nand->ecc.bytes + NFI_FDM_SIZE; + + /* Find the closest supported spare size */ + for (i = 0; i < ARRAY_SIZE(mt7621_nfi_spare_size); i++) { + if (mt7621_nfi_spare_size[i] >= size) + break; + } + + if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_spare_size))) { + pr_err("OOB size (%u) is not supported\n", mtd->oobsize); + return -EINVAL; + } + + nfc->spare_per_sector = mt7621_nfi_spare_size[i]; + + return i; +} + +static int mt7621_nfc_ecc_init(struct mt7621_nfc *nfc) +{ + struct nand_chip *nand = &nfc->nand; + struct mtd_info *mtd = nand_to_mtd(nand); + u32 avail_ecc_bytes, encode_block_size, decode_block_size; + u32 ecc_enccfg, ecc_deccfg; + int ecc_cap; + + nand->ecc.options |= NAND_ECC_CUSTOM_PAGE_ACCESS; + + nand->ecc.size = ECC_SECTOR_SIZE; + nand->ecc.steps = mtd->writesize / nand->ecc.size; + + avail_ecc_bytes = mtd->oobsize / nand->ecc.steps - NFI_FDM_SIZE; + + ecc_cap = mt7621_nfc_calc_ecc_strength(nfc, avail_ecc_bytes); + if (ecc_cap < 0) + return ecc_cap; + + /* Sector + FDM */ + encode_block_size = (nand->ecc.size + NFI_FDM_SIZE) * 8; + ecc_enccfg = ecc_cap | FIELD_PREP(ENC_MODE, ENC_MODE_NFI) | + FIELD_PREP(ENC_CNFG_MSG, encode_block_size); + + /* Sector + FDM + ECC parity bits */ + decode_block_size = ((nand->ecc.size + NFI_FDM_SIZE) * 8) + + nand->ecc.strength * ECC_PARITY_BITS; + ecc_deccfg = ecc_cap | FIELD_PREP(DEC_MODE, DEC_MODE_NFI) | + FIELD_PREP(DEC_CS, decode_block_size) | + FIELD_PREP(DEC_CON, DEC_CON_EL) | DEC_EMPTY_EN; + + mt7621_ecc_encoder_op(nfc, false); + ecc_write32(nfc, ECC_ENCCNFG, ecc_enccfg); + + mt7621_ecc_decoder_op(nfc, false); + ecc_write32(nfc, ECC_DECCNFG, ecc_deccfg); + + return 0; +} + +static int mt7621_nfc_set_page_format(struct mt7621_nfc *nfc) +{ + struct nand_chip *nand = &nfc->nand; + struct mtd_info *mtd = nand_to_mtd(nand); + int i, spare_size; + u32 pagefmt; + + spare_size = mt7621_nfc_set_spare_per_sector(nfc); + if (spare_size < 0) + return spare_size; + + for (i = 0; i < ARRAY_SIZE(mt7621_nfi_page_size); i++) { + if (mt7621_nfi_page_size[i] == mtd->writesize) + break; + } + + if (unlikely(i >= ARRAY_SIZE(mt7621_nfi_page_size))) { + pr_err("Page size (%u) is not supported\n", mtd->writesize); + return -EINVAL; + } + + pagefmt = FIELD_PREP(PAGEFMT_PAGE, i) | + FIELD_PREP(PAGEFMT_SPARE, spare_size) | + FIELD_PREP(PAGEFMT_FDM, NFI_FDM_SIZE) | + FIELD_PREP(PAGEFMT_FDM_ECC, NFI_FDM_SIZE); + + nfi_write16(nfc, NFI_PAGEFMT, pagefmt); + + return 0; +} + +static int mt7621_nfc_attach_chip(struct nand_chip *nand) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(nand); + int ret; + + if (nand->options & NAND_BUSWIDTH_16) { + pr_err("16-bit buswidth is not supported"); + return -EINVAL; + } + + ret = mt7621_nfc_ecc_init(nfc); + if (ret) + return ret; + + return mt7621_nfc_set_page_format(nfc); +} + +static void mt7621_nfc_write_fdm(struct mt7621_nfc *nfc) +{ + struct nand_chip *nand = &nfc->nand; + u32 vall, valm; + u8 *oobptr; + int i, j; + + for (i = 0; i < nand->ecc.steps; i++) { + vall = 0; + valm = 0; + oobptr = oob_fdm_ptr(nand, i); + + for (j = 0; j < 4; j++) + vall |= (u32)oobptr[j] << (j * 8); + + for (j = 0; j < 4; j++) + valm |= (u32)oobptr[j + 4] << (j * 8); + + nfi_write32(nfc, NFI_FDML(i), vall); + nfi_write32(nfc, NFI_FDMM(i), valm); + } +} + +static void mt7621_nfc_read_sector_fdm(struct mt7621_nfc *nfc, u32 sect) +{ + struct nand_chip *nand = &nfc->nand; + u32 vall, valm; + u8 *oobptr; + int i; + + vall = nfi_read32(nfc, NFI_FDML(sect)); + valm = nfi_read32(nfc, NFI_FDMM(sect)); + oobptr = oob_fdm_ptr(nand, sect); + + for (i = 0; i < 4; i++) + oobptr[i] = (vall >> (i * 8)) & 0xff; + + for (i = 0; i < 4; i++) + oobptr[i + 4] = (valm >> (i * 8)) & 0xff; +} + +static int mt7621_nfc_read_page_hwecc(struct mtd_info *mtd, + struct nand_chip *nand, uint8_t *buf, + int oob_required, int page) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(nand); + int bitflips = 0, ret = 0; + int rc, i; + + nand_read_page_op(nand, page, 0, NULL, 0); + + nfi_write16(nfc, NFI_CNFG, FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM) | + CNFG_READ_MODE | CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); + + mt7621_ecc_decoder_op(nfc, true); + + nfi_write16(nfc, NFI_CON, FIELD_PREP(CON_NFI_SEC, nand->ecc.steps) | + CON_NFI_BRD); + + for (i = 0; i < nand->ecc.steps; i++) { + if (buf) + mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i), + nand->ecc.size); + else + mt7621_nfc_read_data_discard(nfc, nand->ecc.size); + + rc = mt7621_ecc_decoder_wait_done(nfc, i); + + mt7621_nfc_read_sector_fdm(nfc, i); + + if (rc < 0) { + ret = -EIO; + continue; + } + + rc = mt7621_ecc_correct_check(nfc, + buf ? page_data_ptr(nand, buf, i) : NULL, + oob_fdm_ptr(nand, i), i); + + if (rc < 0) { + pr_warn("Uncorrectable ECC error at page %d step %d\n", + page, i); + bitflips = nand->ecc.strength + 1; + mtd->ecc_stats.failed++; + } else { + if (rc > bitflips) + bitflips = rc; + mtd->ecc_stats.corrected += rc; + } + } + + mt7621_ecc_decoder_op(nfc, false); + + nfi_write16(nfc, NFI_CON, 0); + + if (ret < 0) + return ret; + + return bitflips; +} + +static int mt7621_nfc_read_page_raw(struct mtd_info *mtd, + struct nand_chip *nand, uint8_t *buf, + int oob_required, int page) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(nand); + int i; + + nand_read_page_op(nand, page, 0, NULL, 0); + + nfi_write16(nfc, NFI_CNFG, FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM) | + CNFG_READ_MODE); + + nfi_write16(nfc, NFI_CON, FIELD_PREP(CON_NFI_SEC, nand->ecc.steps) | + CON_NFI_BRD); + + for (i = 0; i < nand->ecc.steps; i++) { + /* Read data */ + if (buf) + mt7621_nfc_read_data(nfc, page_data_ptr(nand, buf, i), + nand->ecc.size); + else + mt7621_nfc_read_data_discard(nfc, nand->ecc.size); + + /* Read FDM */ + mt7621_nfc_read_data(nfc, oob_fdm_ptr(nand, i), NFI_FDM_SIZE); + + /* Read ECC parity data */ + mt7621_nfc_read_data(nfc, oob_ecc_ptr(nfc, i), + nfc->spare_per_sector - NFI_FDM_SIZE); + } + + nfi_write16(nfc, NFI_CON, 0); + + return 0; +} + +static int mt7621_nfc_read_oob_hwecc(struct mtd_info *mtd, + struct nand_chip *nand, int page) +{ + return mt7621_nfc_read_page_hwecc(mtd, nand, NULL, 1, page); +} + +static int mt7621_nfc_read_oob_raw(struct mtd_info *mtd, + struct nand_chip *nand, int page) +{ + return mt7621_nfc_read_page_raw(mtd, nand, NULL, 1, page); +} + +static int mt7621_nfc_check_empty_page(struct nand_chip *nand, const u8 *buf) +{ + struct mtd_info *mtd = nand_to_mtd(nand); + u8 *oobptr; + u32 i, j; + + if (buf) { + for (i = 0; i < mtd->writesize; i++) + if (buf[i] != 0xff) + return 0; + } + + for (i = 0; i < nand->ecc.steps; i++) { + oobptr = oob_fdm_ptr(nand, i); + for (j = 0; j < NFI_FDM_SIZE; j++) + if (oobptr[j] != 0xff) + return 0; + } + + return 1; +} + +static int mt7621_nfc_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *nand, + const u8 *buf, int oob_required, + int page) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(nand); + + if (mt7621_nfc_check_empty_page(nand, buf)) { + /* + * MT7621 ECC engine always generates parity code for input + * pages, even for empty pages. Doing so will write back ECC + * parity code to the oob region, which means such pages will + * no longer be empty pages. + * + * To avoid this, stop write operation if current page is an + * empty page. + */ + return 0; + } + + nand_prog_page_begin_op(nand, page, 0, NULL, 0); + + nfi_write16(nfc, NFI_CNFG, FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM) | + CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); + + mt7621_ecc_encoder_op(nfc, true); + + mt7621_nfc_write_fdm(nfc); + + nfi_write16(nfc, NFI_CON, FIELD_PREP(CON_NFI_SEC, nand->ecc.steps) | + CON_NFI_BWR); + + if (buf) + mt7621_nfc_write_data(nfc, buf, mtd->writesize); + else + mt7621_nfc_write_data_empty(nfc, mtd->writesize); + + mt7621_nfc_wait_write_completion(nfc, nand); + + mt7621_ecc_encoder_op(nfc, false); + + nfi_write16(nfc, NFI_CON, 0); + + return nand_prog_page_end_op(nand); +} + +static int mt7621_nfc_write_page_raw(struct mtd_info *mtd, + struct nand_chip *nand, + const u8 *buf, int oob_required, + int page) +{ + struct mt7621_nfc *nfc = nand_get_controller_data(nand); + int i; + + nand_prog_page_begin_op(nand, page, 0, NULL, 0); + + nfi_write16(nfc, NFI_CNFG, FIELD_PREP(CNFG_OP_MODE, CNFG_OP_CUSTOM)); + + nfi_write16(nfc, NFI_CON, FIELD_PREP(CON_NFI_SEC, nand->ecc.steps) | + CON_NFI_BWR); + + for (i = 0; i < nand->ecc.steps; i++) { + /* Write data */ + if (buf) + mt7621_nfc_write_data(nfc, page_data_ptr(nand, buf, i), + nand->ecc.size); + else + mt7621_nfc_write_data_empty(nfc, nand->ecc.size); + + /* Write FDM */ + mt7621_nfc_write_data(nfc, oob_fdm_ptr(nand, i), + NFI_FDM_SIZE); + + /* Write dummy ECC parity data */ + mt7621_nfc_write_data_empty(nfc, nfc->spare_per_sector - + NFI_FDM_SIZE); + } + + mt7621_nfc_wait_write_completion(nfc, nand); + + nfi_write16(nfc, NFI_CON, 0); + + return nand_prog_page_end_op(nand); +} + +static int mt7621_nfc_write_oob_hwecc(struct mtd_info *mtd, + struct nand_chip *nand, int page) +{ + return mt7621_nfc_write_page_hwecc(mtd, nand, NULL, 1, page); +} + +static int mt7621_nfc_write_oob_raw(struct mtd_info *mtd, + struct nand_chip *nand, int page) +{ + return mt7621_nfc_write_page_raw(mtd, nand, NULL, 1, page); +} + +static int mt7621_nfc_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oob_region) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + + if (section >= nand->ecc.steps) + return -ERANGE; + + oob_region->length = NFI_FDM_SIZE - 1; + oob_region->offset = section * NFI_FDM_SIZE + 1; + + return 0; +} + +static int mt7621_nfc_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oob_region) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + + if (section) + return -ERANGE; + + oob_region->offset = NFI_FDM_SIZE * nand->ecc.steps; + oob_region->length = mtd->oobsize - oob_region->offset; + + return 0; +} + +static const struct mtd_ooblayout_ops mt7621_nfc_ooblayout_ops = { + .rfree = mt7621_nfc_ooblayout_free, + .ecc = mt7621_nfc_ooblayout_ecc, +}; + +/* + * This function will override the default one which is not supposed to be + * used for ECC syndrome based pages. + */ +static int mt7621_nfc_block_bad(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_chip *nand = mtd_to_nand(mtd); + struct mtd_oob_ops ops; + int ret, i = 0; + u16 bad; + + memset(&ops, 0, sizeof(ops)); + ops.oobbuf = (uint8_t *)&bad; + ops.ooboffs = nand->badblockpos; + if (nand->options & NAND_BUSWIDTH_16) { + ops.ooboffs &= ~0x01; + ops.ooblen = 2; + } else { + ops.ooblen = 1; + } + ops.mode = MTD_OPS_RAW; + + /* Read from first/last page(s) if necessary */ + if (nand->bbt_options & NAND_BBT_SCANLASTPAGE) + ofs += mtd->erasesize - mtd->writesize; + + do { + ret = mtd_read_oob(mtd, ofs, &ops); + if (ret) + return ret; + + if (likely(nand->badblockbits == 8)) + ret = bad != 0xFF; + else + ret = hweight8(bad) < nand->badblockbits; + + i++; + ofs += mtd->writesize; + } while (!ret && (nand->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); + + return ret; +} + +static void mt7621_nfc_init_chip(struct mt7621_nfc *nfc) +{ + struct nand_chip *nand = &nfc->nand; + struct mtd_info *mtd; + int ret; + + nand_set_controller_data(nand, nfc); + + nand->options |= NAND_NO_SUBPAGE_WRITE; + + nand->ecc.mode = NAND_ECC_HW_SYNDROME; + nand->ecc.read_page = mt7621_nfc_read_page_hwecc; + nand->ecc.read_page_raw = mt7621_nfc_read_page_raw; + nand->ecc.write_page = mt7621_nfc_write_page_hwecc; + nand->ecc.write_page_raw = mt7621_nfc_write_page_raw; + nand->ecc.read_oob = mt7621_nfc_read_oob_hwecc; + nand->ecc.read_oob_raw = mt7621_nfc_read_oob_raw; + nand->ecc.write_oob = mt7621_nfc_write_oob_hwecc; + nand->ecc.write_oob_raw = mt7621_nfc_write_oob_raw; + + nand->dev_ready = mt7621_nfc_dev_ready; + nand->select_chip = mt7621_nfc_select_chip; + nand->write_byte = mt7621_nfc_write_byte; + nand->write_buf = mt7621_nfc_write_buf; + nand->read_byte = mt7621_nfc_read_byte; + nand->read_buf = mt7621_nfc_read_buf; + nand->cmd_ctrl = mt7621_nfc_cmd_ctrl; + nand->block_bad = mt7621_nfc_block_bad; + + mtd = nand_to_mtd(nand); + mtd_set_ooblayout(mtd, &mt7621_nfc_ooblayout_ops); + + /* Reset NFI master */ + mt7621_nfc_hw_init(nfc); + + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) + return; + + mt7621_nfc_attach_chip(nand); + + ret = nand_scan_tail(mtd); + if (ret) + return; + + nand_register(0, mtd); +} + +static void mt7621_nfc_set_regs(struct mt7621_nfc *nfc) +{ + nfc->nfi_regs = (void __iomem *)CKSEG1ADDR(NFI_BASE); + nfc->ecc_regs = (void __iomem *)CKSEG1ADDR(NFI_ECC_BASE); +} + +void mt7621_nfc_spl_init(struct mt7621_nfc *nfc) +{ + struct nand_chip *nand = &nfc->nand; + + mt7621_nfc_set_regs(nfc); + + nand_set_controller_data(nand, nfc); + + nand->options |= NAND_NO_SUBPAGE_WRITE; + + nand->ecc.mode = NAND_ECC_HW_SYNDROME; + nand->ecc.read_page = mt7621_nfc_read_page_hwecc; + + nand->dev_ready = mt7621_nfc_dev_ready; + nand->select_chip = mt7621_nfc_select_chip; + nand->read_byte = mt7621_nfc_read_byte; + nand->read_buf = mt7621_nfc_read_buf; + nand->cmd_ctrl = mt7621_nfc_cmd_ctrl; + + /* Reset NFI master */ + mt7621_nfc_hw_init(nfc); +} + +int mt7621_nfc_spl_post_init(struct mt7621_nfc *nfc) +{ + struct nand_chip *nand = &nfc->nand; + int nand_maf_id, nand_dev_id; + struct nand_flash_dev *type; + + type = nand_get_flash_type(&nand->mtd, nand, &nand_maf_id, + &nand_dev_id, NULL); + + if (IS_ERR(type)) + return PTR_ERR(type); + + nand->numchips = 1; + nand->mtd.size = nand->chipsize; + + return mt7621_nfc_attach_chip(nand); +} + +void board_nand_init(void) +{ + mt7621_nfc_set_regs(&nfc_dev); + mt7621_nfc_init_chip(&nfc_dev); +} diff --git a/drivers/mtd/nand/raw/mt7621_nand.h b/drivers/mtd/nand/raw/mt7621_nand.h new file mode 100644 index 00000000000..af4bc55961a --- /dev/null +++ b/drivers/mtd/nand/raw/mt7621_nand.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#ifndef _MT7621_NAND_H_ +#define _MT7621_NAND_H_ + +#include <linux/types.h> +#include <linux/mtd/mtd.h> +#include <linux/compiler.h> +#include <linux/mtd/rawnand.h> + +struct mt7621_nfc { + struct nand_chip nand; + + void __iomem *nfi_regs; + void __iomem *ecc_regs; + + u32 spare_per_sector; +}; + +/* for SPL */ +void mt7621_nfc_spl_init(struct mt7621_nfc *nfc); +int mt7621_nfc_spl_post_init(struct mt7621_nfc *nfc); + +#endif /* _MT7621_NAND_H_ */ diff --git a/drivers/mtd/nand/raw/mt7621_nand_spl.c b/drivers/mtd/nand/raw/mt7621_nand_spl.c new file mode 100644 index 00000000000..114fc8b7cea --- /dev/null +++ b/drivers/mtd/nand/raw/mt7621_nand_spl.c @@ -0,0 +1,237 @@ +// 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 <malloc.h> +#include <linux/sizes.h> +#include <linux/delay.h> +#include <linux/mtd/rawnand.h> +#include "mt7621_nand.h" + +static struct mt7621_nfc nfc_dev; +static u8 *buffer; +static int nand_valid; + +static void nand_command_lp(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + register struct nand_chip *chip = mtd_to_nand(mtd); + + /* Command latch cycle */ + chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + + if (column != -1 || page_addr != -1) { + int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; + + /* Serially input address */ + if (column != -1) { + chip->cmd_ctrl(mtd, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + if (command != NAND_CMD_READID) + chip->cmd_ctrl(mtd, column >> 8, ctrl); + } + if (page_addr != -1) { + chip->cmd_ctrl(mtd, page_addr, ctrl); + chip->cmd_ctrl(mtd, page_addr >> 8, + NAND_NCE | NAND_ALE); + if (chip->options & NAND_ROW_ADDR_3) + chip->cmd_ctrl(mtd, page_addr >> 16, + NAND_NCE | NAND_ALE); + } + } + chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * Program and erase have their own busy handlers status, sequential + * in and status need no delay. + */ + switch (command) { + case NAND_CMD_STATUS: + case NAND_CMD_READID: + case NAND_CMD_SET_FEATURES: + return; + + case NAND_CMD_READ0: + chip->cmd_ctrl(mtd, NAND_CMD_READSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->cmd_ctrl(mtd, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + } + + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ + ndelay(100); + + nand_wait_ready(mtd); +} + +static int nfc_read_page_hwecc(struct mtd_info *mtd, void *buf, + unsigned int page) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int ret; + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); + + ret = chip->ecc.read_page(mtd, chip, buf, 1, page); + if (ret < 0 || ret > chip->ecc.strength) + return -1; + + return 0; +} + +static int nfc_read_oob_hwecc(struct mtd_info *mtd, void *buf, u32 len, + unsigned int page) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + int ret; + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page); + + ret = chip->ecc.read_page(mtd, chip, NULL, 1, page); + if (ret < 0) + return -1; + + if (len > mtd->oobsize) + len = mtd->oobsize; + + memcpy(buf, chip->oob_poi, len); + + return 0; +} + +static int nfc_check_bad_block(struct mtd_info *mtd, unsigned int page) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + u32 pages_per_block, i = 0; + int ret; + u8 bad; + + pages_per_block = 1 << (mtd->erasesize_shift - mtd->writesize_shift); + + /* Read from first/last page(s) if necessary */ + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) { + page += pages_per_block - 1; + if (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) + page--; + } + + do { + ret = nfc_read_oob_hwecc(mtd, &bad, 1, page); + if (ret) + return ret; + + ret = bad != 0xFF; + + i++; + page++; + } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); + + return ret; +} + +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) +{ + struct mt7621_nfc *nfc = &nfc_dev; + struct nand_chip *chip = &nfc->nand; + struct mtd_info *mtd = &chip->mtd; + u32 addr, col, page, chksz; + bool check_bad = true; + + if (!nand_valid) + return -ENODEV; + + while (size) { + if (check_bad || !(offs & mtd->erasesize_mask)) { + addr = offs & (~mtd->erasesize_mask); + page = addr >> mtd->writesize_shift; + if (nfc_check_bad_block(mtd, page)) { + /* Skip bad block */ + if (addr >= mtd->size - mtd->erasesize) + return -1; + + offs += mtd->erasesize; + continue; + } + + check_bad = false; + } + + col = offs & mtd->writesize_mask; + page = offs >> mtd->writesize_shift; + chksz = min(mtd->writesize - col, (uint32_t)size); + + if (unlikely(chksz < mtd->writesize)) { + /* Not reading a full page */ + if (nfc_read_page_hwecc(mtd, buffer, page)) + return -1; + + memcpy(dest, buffer + col, chksz); + } else { + if (nfc_read_page_hwecc(mtd, dest, page)) + return -1; + } + + dest += chksz; + offs += chksz; + size -= chksz; + } + + return 0; +} + +int nand_default_bbt(struct mtd_info *mtd) +{ + return 0; +} + +unsigned long nand_size(void) +{ + if (!nand_valid) + return 0; + + /* Unlikely that NAND size > 2GBytes */ + if (nfc_dev.nand.chipsize <= SZ_2G) + return nfc_dev.nand.chipsize; + + return SZ_2G; +} + +void nand_deselect(void) +{ +} + +void nand_init(void) +{ + struct mtd_info *mtd; + struct nand_chip *chip; + + if (nand_valid) + return; + + mt7621_nfc_spl_init(&nfc_dev); + + chip = &nfc_dev.nand; + mtd = &chip->mtd; + chip->cmdfunc = nand_command_lp; + + if (mt7621_nfc_spl_post_init(&nfc_dev)) + return; + + mtd->erasesize_shift = ffs(mtd->erasesize) - 1; + mtd->writesize_shift = ffs(mtd->writesize) - 1; + mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; + mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; + + buffer = malloc(mtd->writesize); + if (!buffer) + return; + + nand_valid = 1; +} diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c index 666ddeb10d1..4fe7ee0d36a 100644 --- a/drivers/net/mtk_eth.c +++ b/drivers/net/mtk_eth.c @@ -145,7 +145,8 @@ enum mtk_switch { enum mtk_soc { SOC_MT7623, SOC_MT7629, - SOC_MT7622 + SOC_MT7622, + SOC_MT7621 }; struct mtk_eth_priv { @@ -159,9 +160,10 @@ struct mtk_eth_priv { void __iomem *fe_base; void __iomem *gmac_base; - void __iomem *ethsys_base; void __iomem *sgmii_base; + struct regmap *ethsys_regmap; + struct mii_dev *mdio_bus; int (*mii_read)(struct mtk_eth_priv *priv, u8 phy, u8 reg); int (*mii_write)(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 val); @@ -233,7 +235,12 @@ static void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set) static void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set) { - clrsetbits_le32(priv->ethsys_base + reg, clr, set); + uint val; + + regmap_read(priv->ethsys_regmap, reg, &val); + val &= ~clr; + val |= set; + regmap_write(priv->ethsys_regmap, reg, val); } /* Direct MDIO clause 22/45 access via SoC */ @@ -669,12 +676,18 @@ static int mt7530_pad_clk_setup(struct mtk_eth_priv *priv, int mode) static int mt7530_setup(struct mtk_eth_priv *priv) { u16 phy_addr, phy_val; - u32 val; + u32 val, txdrv; int i; - /* Select 250MHz clk for RGMII mode */ - mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG, - ETHSYS_TRGMII_CLK_SEL362_5, 0); + if (priv->soc != SOC_MT7621) { + /* Select 250MHz clk for RGMII mode */ + mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG, + ETHSYS_TRGMII_CLK_SEL362_5, 0); + + txdrv = 8; + } else { + txdrv = 4; + } /* Modify HWTRAP first to allow direct access to internal PHYs */ mt753x_reg_read(priv, HWTRAP_REG, &val); @@ -732,7 +745,8 @@ static int mt7530_setup(struct mtk_eth_priv *priv) /* Lower Tx Driving for TRGMII path */ for (i = 0 ; i < NUM_TRGMII_CTRL ; i++) mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i), - (8 << TD_DM_DRVP_S) | (8 << TD_DM_DRVN_S)); + (txdrv << TD_DM_DRVP_S) | + (txdrv << TD_DM_DRVN_S)); for (i = 0 ; i < NUM_TRGMII_CTRL; i++) mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16); @@ -1419,7 +1433,7 @@ static int mtk_eth_of_to_plat(struct udevice *dev) priv->soc = dev_get_driver_data(dev); - pdata->iobase = dev_read_addr(dev); + pdata->iobase = (phys_addr_t)dev_remap_addr(dev); /* get corresponding ethsys phandle */ ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0, @@ -1427,15 +1441,9 @@ static int mtk_eth_of_to_plat(struct udevice *dev) if (ret) return ret; - regmap = syscon_node_to_regmap(args.node); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - priv->ethsys_base = regmap_get_range(regmap, 0); - if (!priv->ethsys_base) { - dev_err(dev, "Unable to find ethsys\n"); - return -ENODEV; - } + priv->ethsys_regmap = syscon_node_to_regmap(args.node); + if (IS_ERR(priv->ethsys_regmap)) + return PTR_ERR(priv->ethsys_regmap); /* Reset controllers */ ret = reset_get_by_name(dev, "fe", &priv->rst_fe); @@ -1540,6 +1548,7 @@ static const struct udevice_id mtk_eth_ids[] = { { .compatible = "mediatek,mt7629-eth", .data = SOC_MT7629 }, { .compatible = "mediatek,mt7623-eth", .data = SOC_MT7623 }, { .compatible = "mediatek,mt7622-eth", .data = SOC_MT7622 }, + { .compatible = "mediatek,mt7621-eth", .data = SOC_MT7621 }, {} }; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 4a3856d3c2f..c25b42c68f5 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -266,7 +266,7 @@ config MT76X8_USB_PHY config PHY_MTK_TPHY bool "MediaTek T-PHY Driver" depends on PHY - depends on ARCH_MEDIATEK + depends on ARCH_MEDIATEK || SOC_MT7621 help MediaTek T-PHY driver supports usb2.0, usb3.0 ports, PCIe and SATA, and meanwhile supports two version T-PHY which have diff --git a/drivers/pinctrl/mtmips/Kconfig b/drivers/pinctrl/mtmips/Kconfig index 844d5b743fe..456f3ea25d2 100644 --- a/drivers/pinctrl/mtmips/Kconfig +++ b/drivers/pinctrl/mtmips/Kconfig @@ -12,6 +12,15 @@ config PINCTRL_MT7620 The driver is controlled by a device tree node which contains the pin mux functions for each available pin groups. +config PINCTRL_MT7621 + bool "MediaTek MT7621 pin control driver" + select PINCTRL_MTMIPS + depends on SOC_MT7621 && PINCTRL_GENERIC + help + Support pin multiplexing control on MediaTek MT7621. + The driver is controlled by a device tree node which contains + the pin mux functions for each available pin groups. + config PINCTRL_MT7628 bool "MediaTek MT7628 pin control driver" select PINCTRL_MTMIPS diff --git a/drivers/pinctrl/mtmips/Makefile b/drivers/pinctrl/mtmips/Makefile index ba945a89a76..8fece4f5fa9 100644 --- a/drivers/pinctrl/mtmips/Makefile +++ b/drivers/pinctrl/mtmips/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_PINCTRL_MTMIPS) += pinctrl-mtmips-common.o # SoC Drivers obj-$(CONFIG_PINCTRL_MT7620) += pinctrl-mt7620.o +obj-$(CONFIG_PINCTRL_MT7621) += pinctrl-mt7621.o obj-$(CONFIG_PINCTRL_MT7628) += pinctrl-mt7628.o diff --git a/drivers/pinctrl/mtmips/pinctrl-mt7621.c b/drivers/pinctrl/mtmips/pinctrl-mt7621.c new file mode 100644 index 00000000000..3e98a01bad4 --- /dev/null +++ b/drivers/pinctrl/mtmips/pinctrl-mt7621.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#include <dm.h> +#include <dm/pinctrl.h> +#include <dm/device_compat.h> +#include <linux/bitops.h> +#include <linux/io.h> + +#include "pinctrl-mtmips-common.h" + +#define SYSC_MAP_SIZE 0x100 + +#define PAD_UART1_GPIO0_OFS 0x00 +#define PAD_UART3_I2C_OFS 0x04 +#define PAD_UART2_JTAG_OFS 0x08 +#define PAD_PERST_WDT_OFS 0x0c +#define PAD_RGMII2_MDIO_OFS 0x10 +#define PAD_SDXC_SPI_OFS 0x14 +#define GPIOMODE_OFS 0x18 +#define PAD_BOPT_ESWINT_OFS 0x28 + +#define ESWINT_SHIFT 20 +#define SDXC_SHIFT 18 +#define SPI_SHIFT 16 +#define RGMII2_SHIFT 15 +#define RGMII1_SHIFT 14 +#define MDIO_SHIFT 12 +#define PERST_SHIFT 10 +#define WDT_SHIFT 8 +#define JTAG_SHIFT 7 +#define UART2_SHIFT 5 +#define UART3_SHIFT 3 +#define I2C_SHIFT 2 +#define UART1_SHIFT 1 +#define GPIO0_SHIFT 0 /* Dummy */ + +#define GM4_MASK 3 + +#define E4_E2_M 0x03 +#define E4_E2_S 4 +#define PULL_UP BIT(3) +#define PULL_DOWN BIT(2) +#define SMT BIT(1) +#define SR BIT(0) + +struct mt7621_pinctrl_priv { + struct mtmips_pinctrl_priv mp; +}; + +#if CONFIG_IS_ENABLED(PINMUX) +static const struct mtmips_pmx_func esw_int_grp[] = { + FUNC("gpio", 1), + FUNC("esw int", 0), +}; + +static const struct mtmips_pmx_func sdxc_grp[] = { + FUNC("nand", 2), + FUNC("gpio", 1), + FUNC("sdxc", 0), +}; + +static const struct mtmips_pmx_func spi_grp[] = { + FUNC("nand", 2), + FUNC("gpio", 1), + FUNC("spi", 0), +}; + +static const struct mtmips_pmx_func rgmii2_grp[] = { + FUNC("gpio", 1), + FUNC("rgmii", 0), +}; + +static const struct mtmips_pmx_func rgmii1_grp[] = { + FUNC("gpio", 1), + FUNC("rgmii", 0), +}; + +static const struct mtmips_pmx_func mdio_grp[] = { + FUNC("gpio", 1), + FUNC("mdio", 0), +}; + +static const struct mtmips_pmx_func perst_grp[] = { + FUNC("refclk", 2), + FUNC("gpio", 1), + FUNC("pcie reset", 0), +}; + +static const struct mtmips_pmx_func wdt_grp[] = { + FUNC("refclk", 2), + FUNC("gpio", 1), + FUNC("wdt rst", 0), +}; + +static const struct mtmips_pmx_func jtag_grp[] = { + FUNC("gpio", 1), + FUNC("jtag", 0), +}; + +static const struct mtmips_pmx_func uart2_grp[] = { + FUNC("spdif", 3), + FUNC("pcm", 2), + FUNC("gpio", 1), + FUNC("uart", 0), +}; + +static const struct mtmips_pmx_func uart3_grp[] = { + FUNC("spdif", 3), + FUNC("i2s", 2), + FUNC("gpio", 1), + FUNC("uart", 0), +}; + +static const struct mtmips_pmx_func i2c_grp[] = { + FUNC("gpio", 1), + FUNC("i2c", 0), +}; + +static const struct mtmips_pmx_func uart1_grp[] = { + FUNC("gpio", 1), + FUNC("uart", 0), +}; + +static const struct mtmips_pmx_func gpio0_grp[] = { + FUNC("gpio", 0), +}; + +static const struct mtmips_pmx_group mt7621_pmx_data[] = { + GRP_PCONF("esw int", esw_int_grp, GPIOMODE_OFS, ESWINT_SHIFT, 1, + PAD_BOPT_ESWINT_OFS, 0), + GRP_PCONF("sdxc", sdxc_grp, GPIOMODE_OFS, SDXC_SHIFT, GM4_MASK, + PAD_SDXC_SPI_OFS, 16), + GRP_PCONF("spi", spi_grp, GPIOMODE_OFS, SPI_SHIFT, GM4_MASK, + PAD_SDXC_SPI_OFS, 0), + GRP_PCONF("rgmii2", rgmii2_grp, GPIOMODE_OFS, RGMII2_SHIFT, 1, + PAD_RGMII2_MDIO_OFS, 16), + GRP("rgmii1", rgmii1_grp, GPIOMODE_OFS, RGMII1_SHIFT, 1), + GRP_PCONF("mdio", mdio_grp, GPIOMODE_OFS, MDIO_SHIFT, GM4_MASK, + PAD_RGMII2_MDIO_OFS, 0), + GRP_PCONF("pcie reset", perst_grp, GPIOMODE_OFS, PERST_SHIFT, GM4_MASK, + PAD_PERST_WDT_OFS, 16), + GRP_PCONF("wdt", wdt_grp, GPIOMODE_OFS, WDT_SHIFT, GM4_MASK, + PAD_PERST_WDT_OFS, 0), + GRP_PCONF("jtag", jtag_grp, GPIOMODE_OFS, JTAG_SHIFT, 1, + PAD_UART2_JTAG_OFS, 16), + GRP_PCONF("uart2", uart2_grp, GPIOMODE_OFS, UART2_SHIFT, GM4_MASK, + PAD_UART2_JTAG_OFS, 0), + GRP_PCONF("uart3", uart3_grp, GPIOMODE_OFS, UART3_SHIFT, GM4_MASK, + PAD_UART3_I2C_OFS, 16), + GRP_PCONF("i2c", i2c_grp, GPIOMODE_OFS, I2C_SHIFT, 1, + PAD_UART3_I2C_OFS, 0), + GRP_PCONF("uart1", uart1_grp, GPIOMODE_OFS, UART1_SHIFT, 1, + PAD_UART1_GPIO0_OFS, 16), + GRP_PCONF("gpio0", gpio0_grp, GPIOMODE_OFS, GPIO0_SHIFT, 1, + PAD_UART1_GPIO0_OFS, 0), +}; + +static int mt7621_get_groups_count(struct udevice *dev) +{ + return ARRAY_SIZE(mt7621_pmx_data); +} + +static const char *mt7621_get_group_name(struct udevice *dev, + unsigned int selector) +{ + return mt7621_pmx_data[selector].name; +} +#endif /* CONFIG_IS_ENABLED(PINMUX) */ + +#if CONFIG_IS_ENABLED(PINCONF) +static const struct pinconf_param mt7621_conf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, + { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 0 }, +}; + +static const u32 mt7621_pconf_drv_strength_tbl[] = {2, 4, 6, 8}; + +static int mt7621_pinconf_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int param, unsigned int arg) +{ + struct mt7621_pinctrl_priv *priv = dev_get_priv(dev); + const struct mtmips_pmx_group *grp = &mt7621_pmx_data[group_selector]; + u32 clr = 0, set = 0; + int i; + + if (!grp->pconf_avail) + return 0; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + clr = PULL_UP | PULL_DOWN; + break; + + case PIN_CONFIG_BIAS_PULL_UP: + clr = PULL_DOWN; + set = PULL_UP; + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + clr = PULL_UP; + set = PULL_DOWN; + break; + + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (arg) + set = SMT; + else + clr = SMT; + break; + + case PIN_CONFIG_DRIVE_STRENGTH: + for (i = 0; i < ARRAY_SIZE(mt7621_pconf_drv_strength_tbl); i++) + if (mt7621_pconf_drv_strength_tbl[i] == arg) + break; + + if (i >= ARRAY_SIZE(mt7621_pconf_drv_strength_tbl)) + return -EINVAL; + + clr = E4_E2_M << E4_E2_S; + set = i << E4_E2_S; + break; + + case PIN_CONFIG_SLEW_RATE: + if (arg) + set = SR; + else + clr = SR; + break; + + default: + return -EINVAL; + } + + mtmips_pinctrl_reg_set(&priv->mp, grp->pconf_reg, grp->pconf_shift, + clr, set); + + return 0; +} +#endif + +static int mt7621_pinctrl_probe(struct udevice *dev) +{ + struct mt7621_pinctrl_priv *priv = dev_get_priv(dev); + int ret = 0; + +#if CONFIG_IS_ENABLED(PINMUX) + ret = mtmips_pinctrl_probe(&priv->mp, ARRAY_SIZE(mt7621_pmx_data), + mt7621_pmx_data); +#endif /* CONFIG_IS_ENABLED(PINMUX) */ + + return ret; +} + +static int mt7621_pinctrl_of_to_plat(struct udevice *dev) +{ + struct mt7621_pinctrl_priv *priv = dev_get_priv(dev); + + priv->mp.base = (void __iomem *)dev_remap_addr_index(dev, 0); + + if (!priv->mp.base) + return -EINVAL; + + return 0; +} + +static const struct pinctrl_ops mt7621_pinctrl_ops = { +#if CONFIG_IS_ENABLED(PINMUX) + .get_groups_count = mt7621_get_groups_count, + .get_group_name = mt7621_get_group_name, + .get_functions_count = mtmips_get_functions_count, + .get_function_name = mtmips_get_function_name, + .pinmux_group_set = mtmips_pinmux_group_set, +#endif /* CONFIG_IS_ENABLED(PINMUX) */ +#if CONFIG_IS_ENABLED(PINCONF) + .pinconf_num_params = ARRAY_SIZE(mt7621_conf_params), + .pinconf_params = mt7621_conf_params, + .pinconf_group_set = mt7621_pinconf_group_set, +#endif /* CONFIG_IS_ENABLED(PINCONF) */ + .set_state = pinctrl_generic_set_state, +}; + +static const struct udevice_id mt7621_pinctrl_ids[] = { + { .compatible = "mediatek,mt7621-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(mt7621_pinctrl) = { + .name = "mt7621-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = mt7621_pinctrl_ids, + .of_to_plat = mt7621_pinctrl_of_to_plat, + .ops = &mt7621_pinctrl_ops, + .probe = mt7621_pinctrl_probe, + .priv_auto = sizeof(struct mt7621_pinctrl_priv), +}; diff --git a/drivers/pinctrl/mtmips/pinctrl-mtmips-common.c b/drivers/pinctrl/mtmips/pinctrl-mtmips-common.c index e361916eb28..869b7810685 100644 --- a/drivers/pinctrl/mtmips/pinctrl-mtmips-common.c +++ b/drivers/pinctrl/mtmips/pinctrl-mtmips-common.c @@ -13,8 +13,8 @@ #include "pinctrl-mtmips-common.h" -static void mtmips_pinctrl_reg_set(struct mtmips_pinctrl_priv *priv, - u32 reg, u32 shift, u32 mask, u32 value) +void mtmips_pinctrl_reg_set(struct mtmips_pinctrl_priv *priv, + u32 reg, u32 shift, u32 mask, u32 value) { u32 val; diff --git a/drivers/pinctrl/mtmips/pinctrl-mtmips-common.h b/drivers/pinctrl/mtmips/pinctrl-mtmips-common.h index b51d8f009c0..1f1023ef421 100644 --- a/drivers/pinctrl/mtmips/pinctrl-mtmips-common.h +++ b/drivers/pinctrl/mtmips/pinctrl-mtmips-common.h @@ -22,6 +22,10 @@ struct mtmips_pmx_group { u32 shift; char mask; + int pconf_avail; + u32 pconf_reg; + u32 pconf_shift; + int nfuncs; const struct mtmips_pmx_func *funcs; }; @@ -42,6 +46,14 @@ struct mtmips_pinctrl_priv { { .name = (_name), .reg = (_reg), .shift = (_shift), .mask = (_mask), \ .funcs = (_funcs), .nfuncs = ARRAY_SIZE(_funcs) } +#define GRP_PCONF(_name, _funcs, _reg, _shift, _mask, _pconf_reg, _pconf_shift) \ + { .name = (_name), .reg = (_reg), .shift = (_shift), .mask = (_mask), \ + .funcs = (_funcs), .nfuncs = ARRAY_SIZE(_funcs), .pconf_avail = 1, \ + .pconf_reg = (_pconf_reg), .pconf_shift = (_pconf_shift) } + +void mtmips_pinctrl_reg_set(struct mtmips_pinctrl_priv *priv, + u32 reg, u32 shift, u32 mask, u32 value); + int mtmips_get_functions_count(struct udevice *dev); const char *mtmips_get_function_name(struct udevice *dev, unsigned int selector); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 766d5636c09..75b794548b2 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -254,7 +254,7 @@ config MT7620_SPI config MT7621_SPI bool "MediaTek MT7621 SPI driver" - depends on SOC_MT7628 + depends on SOC_MT7621 || SOC_MT7628 help Enable the MT7621 SPI driver. This driver can be used to access the SPI NOR flash on platforms embedding this Ralink / MediaTek diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 31ae9f74e7a..c3b97f48f0f 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -42,7 +42,7 @@ config USB_XHCI_EXYNOS config USB_XHCI_MTK bool "Support for MediaTek on-chip xHCI USB controller" - depends on ARCH_MEDIATEK + depends on ARCH_MEDIATEK || SOC_MT7621 help Enables support for the on-chip xHCI controller on MediaTek SoCs. diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 532ada89c1b..6043fe717fb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -191,7 +191,7 @@ config WDT_MT7620 config WDT_MT7621 bool "MediaTek MT7621 watchdog timer support" - depends on WDT && SOC_MT7628 + depends on WDT && (SOC_MT7621 || SOC_MT7628) help Select this to enable Ralink / Mediatek watchdog timer, which can be found on some MediaTek chips. diff --git a/include/configs/mt7621.h b/include/configs/mt7621.h new file mode 100644 index 00000000000..1f689970803 --- /dev/null +++ b/include/configs/mt7621.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#ifndef __CONFIG_MT7621_H +#define __CONFIG_MT7621_H + +#define CONFIG_SYS_MIPS_TIMER_FREQ 440000000 + +#define CONFIG_SYS_SDRAM_BASE 0x80000000 + +#define CONFIG_VERY_BIG_RAM +#define CONFIG_MAX_MEM_MAPPED 0x1c000000 + +#define CONFIG_SYS_INIT_SP_OFFSET 0x800000 + +#define CONFIG_SYS_NONCACHED_MEMORY 0x100000 + +/* MMC */ +#define MMC_SUPPORTS_TUNING + +/* NAND */ +#define CONFIG_SYS_MAX_NAND_DEVICE 1 + +/* Serial SPL */ +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_SERIAL) +#define CONFIG_SYS_NS16550_MEM32 +#define CONFIG_SYS_NS16550_CLK 50000000 +#define CONFIG_SYS_NS16550_REG_SIZE -4 +#define CONFIG_SYS_NS16550_COM1 0xbe000c00 +#endif + +/* Serial common */ +#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200, \ + 230400, 460800, 921600 } + +/* Dummy value */ +#define CONFIG_SYS_UBOOT_BASE 0 + +#endif /* __CONFIG_MT7621_H */ diff --git a/include/dt-bindings/clock/mt7621-clk.h b/include/dt-bindings/clock/mt7621-clk.h new file mode 100644 index 00000000000..978c67951ba --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#ifndef _DT_BINDINGS_MT7621_CLK_H_ +#define _DT_BINDINGS_MT7621_CLK_H_ + +#define MT7621_CLK_XTAL 0 +#define MT7621_CLK_CPU 1 +#define MT7621_CLK_BUS 2 +#define MT7621_CLK_50M 3 +#define MT7621_CLK_125M 4 +#define MT7621_CLK_150M 5 +#define MT7621_CLK_250M 6 +#define MT7621_CLK_270M 7 + +#define MT7621_CLK_HSDMA 8 +#define MT7621_CLK_FE 9 +#define MT7621_CLK_SP_DIVTX 10 +#define MT7621_CLK_TIMER 11 +#define MT7621_CLK_PCM 12 +#define MT7621_CLK_PIO 13 +#define MT7621_CLK_GDMA 14 +#define MT7621_CLK_NAND 15 +#define MT7621_CLK_I2C 16 +#define MT7621_CLK_I2S 17 +#define MT7621_CLK_SPI 18 +#define MT7621_CLK_UART1 19 +#define MT7621_CLK_UART2 20 +#define MT7621_CLK_UART3 21 +#define MT7621_CLK_ETH 22 +#define MT7621_CLK_PCIE0 23 +#define MT7621_CLK_PCIE1 24 +#define MT7621_CLK_PCIE2 25 +#define MT7621_CLK_CRYPTO 26 +#define MT7621_CLK_SHXC 27 + +#define MT7621_CLK_MAX 28 + +/* for u-boot only */ +#define MT7621_CLK_DDR 29 + +#endif /* _DT_BINDINGS_MT7621_CLK_H_ */ diff --git a/include/dt-bindings/reset/mt7621-reset.h b/include/dt-bindings/reset/mt7621-reset.h new file mode 100644 index 00000000000..8e4341f0407 --- /dev/null +++ b/include/dt-bindings/reset/mt7621-reset.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao <weijie.gao@mediatek.com> + */ + +#ifndef _DT_BINDINGS_MT7621_RESET_H_ +#define _DT_BINDINGS_MT7621_RESET_H_ + +#define RST_PPE 31 +#define RST_SDXC 30 +#define RST_CRYPTO 29 +#define RST_AUX_STCK 28 +#define RST_PCIE2 26 +#define RST_PCIE1 25 +#define RST_PCIE0 24 +#define RST_GMAC 23 +#define RST_UART3 21 +#define RST_UART2 20 +#define RST_UART1 19 +#define RST_SPI 18 +#define RST_I2S 17 +#define RST_I2C 16 +#define RST_NFI 15 +#define RST_GDMA 14 +#define RST_PIO 13 +#define RST_PCM 11 +#define RST_MC 10 +#define RST_INTC 9 +#define RST_TIMER 8 +#define RST_SPDIFTX 7 +#define RST_FE 6 +#define RST_HSDMA 5 +#define RST_MCM 2 +#define RST_SYS 0 + +#endif /* _DT_BINDINGS_MT7621_RESET_H_ */ diff --git a/tools/mtk_image.c b/tools/mtk_image.c index 418c5fd54b4..de5ce4d964c 100644 --- a/tools/mtk_image.c +++ b/tools/mtk_image.c @@ -6,7 +6,9 @@ * Author: Weijie Gao <weijie.gao@mediatek.com> */ +#include <time.h> #include <image.h> +#include <u-boot/crc.h> #include <u-boot/sha256.h> #include "imagetool.h" #include "mtk_image.h" @@ -251,17 +253,45 @@ static uint32_t img_size; static enum brlyt_img_type hdr_media; static uint32_t hdr_offset; static int use_lk_hdr; +static int use_mt7621_hdr; static bool is_arm64_image; /* LK image name */ static char lk_name[32] = "U-Boot"; +/* CRC32 normal table required by MT7621 image */ +static uint32_t crc32tbl[256]; + /* NAND header selected by user */ static const union nand_boot_header *hdr_nand; /* GFH header + 2 * 4KB pages of NAND */ static char hdr_tmp[sizeof(struct gfh_header) + 0x2000]; +static uint32_t crc32_normal_cal(uint32_t crc, const void *data, size_t length, + const uint32_t *crc32c_table) +{ + const uint8_t *p = data; + + while (length--) + crc = crc32c_table[(uint8_t)((crc >> 24) ^ *p++)] ^ (crc << 8); + + return crc; +} + +static void crc32_normal_init(uint32_t *crc32c_table, uint32_t poly) +{ + uint32_t v, i, j; + + for (i = 0; i < 256; i++) { + v = i << 24; + for (j = 0; j < 8; j++) + v = (v << 1) ^ ((v & (1 << 31)) ? poly : 0); + + crc32c_table[i] = v; + } +} + static int mtk_image_check_image_types(uint8_t type) { if (type == IH_TYPE_MTKIMAGE) @@ -283,6 +313,7 @@ static int mtk_brom_parse_imagename(const char *imagename) static const char *hdr_offs = ""; static const char *nandinfo = ""; static const char *lk = ""; + static const char *mt7621 = ""; static const char *arm64_param = ""; key = buf; @@ -332,6 +363,9 @@ static int mtk_brom_parse_imagename(const char *imagename) if (!strcmp(key, "lk")) lk = val; + if (!strcmp(key, "mt7621")) + mt7621 = val; + if (!strcmp(key, "lkname")) snprintf(lk_name, sizeof(lk_name), "%s", val); @@ -352,6 +386,13 @@ static int mtk_brom_parse_imagename(const char *imagename) return 0; } + /* if user specified MT7621 image header, skip following checks */ + if (mt7621 && mt7621[0] == '1') { + use_mt7621_hdr = 1; + free(buf); + return 0; + } + /* parse media type */ for (i = 0; i < ARRAY_SIZE(brom_images); i++) { if (!strcmp(brom_images[i].name, media)) { @@ -419,6 +460,13 @@ static int mtk_image_vrec_header(struct image_tool_params *params, return 0; } + if (use_mt7621_hdr) { + tparams->header_size = image_get_header_size(); + tparams->hdr = &hdr_tmp; + memset(&hdr_tmp, 0, tparams->header_size); + return 0; + } + if (hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND) tparams->header_size = 2 * le16_to_cpu(hdr_nand->pagesize); else @@ -579,9 +627,90 @@ static int mtk_image_verify_nand_header(const uint8_t *ptr, int print) return 0; } +static uint32_t crc32be_cal(const void *data, size_t length) +{ + uint32_t crc = 0; + uint8_t c; + + if (crc32tbl[1] != MT7621_IH_CRC_POLYNOMIAL) + crc32_normal_init(crc32tbl, MT7621_IH_CRC_POLYNOMIAL); + + crc = crc32_normal_cal(crc, data, length, crc32tbl); + + for (; length; length >>= 8) { + c = length & 0xff; + crc = crc32_normal_cal(crc, &c, 1, crc32tbl); + } + + return ~crc; +} + +static int mtk_image_verify_mt7621_header(const uint8_t *ptr, int print) +{ + const image_header_t *hdr = (const image_header_t *)ptr; + struct mt7621_nand_header *nhdr; + uint32_t spl_size, crcval; + image_header_t header; + int ret; + + spl_size = image_get_size(hdr); + + if (spl_size > img_size) { + if (print) + printf("Incomplete SPL image\n"); + return -1; + } + + ret = image_check_hcrc(hdr); + if (!ret) { + if (print) + printf("Bad header CRC\n"); + return -1; + } + + ret = image_check_dcrc(hdr); + if (!ret) { + if (print) + printf("Bad data CRC\n"); + return -1; + } + + /* Copy header so we can blank CRC field for re-calculation */ + memmove(&header, hdr, image_get_header_size()); + image_set_hcrc(&header, 0); + + nhdr = (struct mt7621_nand_header *)header.ih_name; + crcval = be32_to_cpu(nhdr->crc); + nhdr->crc = 0; + + if (crcval != crc32be_cal(&header, image_get_header_size())) { + if (print) + printf("Bad NAND header CRC\n"); + return -1; + } + + if (print) { + printf("Load Address: %08x\n", image_get_load(hdr)); + + printf("Image Name: %.*s\n", MT7621_IH_NMLEN, + image_get_name(hdr)); + + if (IMAGE_ENABLE_TIMESTAMP) { + printf("Created: "); + genimg_print_time((time_t)image_get_time(hdr)); + } + + printf("Data Size: "); + genimg_print_size(image_get_data_size(hdr)); + } + + return 0; +} + static int mtk_image_verify_header(unsigned char *ptr, int image_size, struct image_tool_params *params) { + image_header_t *hdr = (image_header_t *)ptr; union lk_hdr *lk = (union lk_hdr *)ptr; /* nothing to verify for LK image header */ @@ -590,6 +719,9 @@ static int mtk_image_verify_header(unsigned char *ptr, int image_size, img_size = image_size; + if (image_get_magic(hdr) == IH_MAGIC) + return mtk_image_verify_mt7621_header(ptr, 0); + if (!strcmp((char *)ptr, NAND_BOOT_NAME)) return mtk_image_verify_nand_header(ptr, 0); else @@ -600,6 +732,7 @@ static int mtk_image_verify_header(unsigned char *ptr, int image_size, static void mtk_image_print_header(const void *ptr) { + image_header_t *hdr = (image_header_t *)ptr; union lk_hdr *lk = (union lk_hdr *)ptr; if (le32_to_cpu(lk->magic) == LK_PART_MAGIC) { @@ -610,6 +743,11 @@ static void mtk_image_print_header(const void *ptr) printf("Image Type: MediaTek BootROM Loadable Image\n"); + if (image_get_magic(hdr) == IH_MAGIC) { + mtk_image_verify_mt7621_header(ptr, 1); + return; + } + if (!strcmp((char *)ptr, NAND_BOOT_NAME)) mtk_image_verify_nand_header(ptr, 1); else @@ -773,6 +911,45 @@ static void mtk_image_set_nand_header(void *ptr, off_t filesize, filesize - 2 * le16_to_cpu(hdr_nand->pagesize) - SHA256_SUM_LEN); } +static void mtk_image_set_mt7621_header(void *ptr, off_t filesize, + uint32_t loadaddr) +{ + image_header_t *hdr = (image_header_t *)ptr; + struct mt7621_stage1_header *shdr; + struct mt7621_nand_header *nhdr; + uint32_t datasize, crcval; + + datasize = filesize - image_get_header_size(); + nhdr = (struct mt7621_nand_header *)hdr->ih_name; + shdr = (struct mt7621_stage1_header *)(ptr + image_get_header_size()); + + shdr->ep = cpu_to_be32(loadaddr); + shdr->stage_size = cpu_to_be32(datasize); + + image_set_magic(hdr, IH_MAGIC); + image_set_time(hdr, time(NULL)); + image_set_size(hdr, datasize); + image_set_load(hdr, loadaddr); + image_set_ep(hdr, loadaddr); + image_set_os(hdr, IH_OS_U_BOOT); + image_set_arch(hdr, IH_ARCH_MIPS); + image_set_type(hdr, IH_TYPE_STANDALONE); + image_set_comp(hdr, IH_COMP_NONE); + + crcval = crc32(0, (uint8_t *)shdr, datasize); + image_set_dcrc(hdr, crcval); + + strncpy(nhdr->ih_name, "MT7621 NAND", MT7621_IH_NMLEN); + + nhdr->ih_stage_offset = cpu_to_be32(image_get_header_size()); + + crcval = crc32be_cal(hdr, image_get_header_size()); + nhdr->crc = cpu_to_be32(crcval); + + crcval = crc32(0, (uint8_t *)hdr, image_get_header_size()); + image_set_hcrc(hdr, crcval); +} + static void mtk_image_set_header(void *ptr, struct stat *sbuf, int ifd, struct image_tool_params *params) { @@ -791,6 +968,11 @@ static void mtk_image_set_header(void *ptr, struct stat *sbuf, int ifd, img_gen = true; img_size = sbuf->st_size; + if (use_mt7621_hdr) { + mtk_image_set_mt7621_header(ptr, sbuf->st_size, params->addr); + return; + } + if (hdr_media == BRLYT_TYPE_NAND || hdr_media == BRLYT_TYPE_SNAND) mtk_image_set_nand_header(ptr, sbuf->st_size, params->addr); else diff --git a/tools/mtk_image.h b/tools/mtk_image.h index 7dda71ce88a..d868545a33f 100644 --- a/tools/mtk_image.h +++ b/tools/mtk_image.h @@ -200,4 +200,28 @@ union lk_hdr { #define LK_PART_MAGIC 0x58881688 +/* MT7621 NAND SPL image header */ + +#define MT7621_IH_NMLEN 12 +#define MT7621_IH_CRC_POLYNOMIAL 0x04c11db7 + +struct mt7621_nand_header { + char ih_name[MT7621_IH_NMLEN]; + uint32_t nand_ac_timing; + uint32_t ih_stage_offset; + uint32_t ih_bootloader_offset; + uint32_t nand_info_1_data; + uint32_t crc; +}; + +struct mt7621_stage1_header { + uint32_t jump_insn[2]; + uint32_t ep; + uint32_t stage_size; + uint32_t has_stage2; + uint32_t next_ep; + uint32_t next_size; + uint32_t next_offset; +}; + #endif /* _MTK_IMAGE_H */ |