[PATCH v2 00/14] Add support for MediaTek MT7621 SoC

This series will add support for MediaTek MT7621 SoC with two reference boards and related drivers.
The MediaTek MT7621 is a network processor integrating a dual-core dual-threaded MIPS 1004Kc processor running at a normal frequency of 880MHz. This chip can be found in many wireless routers.
This series add all basic drivers which are useful in u-boot, like usb, sdxc, ethernet, spi, nand and serial.
Currently this patch series only supports building the ram-bootable image as it needs the preloader from MediaTek SDK.
Thanks, Weijie
v2 changes: - Add a kconfig for max supported ram size - Remove network configs from default config file - Add config file for mt7621-rfb boards
Weijie Gao (14): mips: mtmips: add support for MediaTek MT7621 SoC mips: mtmips: add two reference boards for mt7621 clk: mtmips: add clock driver for MediaTek MT7621 SoC reset: mtmips: add reset controller support for MediaTek MT7621 SoC pinctrl: mtmips: add support for MediaTek MT7621 SoC nand: raw: add support for MediaTek MT7621 SoC usb: xhci-mtk: add support for MediaTek MT7621 SoC phy: mtk-tphy: add support for MediaTek MT7621 SoC spi: add support for MediaTek MT7621 SoC gpio: add support for MediaTek MT7621 SoC watchdog: add support for MediaTek MT7621 SoC mmc: mediatek: add support for MediaTek MT7621 SoC net: mediatek: add support for MediaTek MT7621 SoC MAINTAINERS: update maintainer for MediaTek MIPS platform
MAINTAINERS | 5 + arch/mips/dts/Makefile | 2 + arch/mips/dts/mediatek,mt7621-nand-rfb.dts | 52 + arch/mips/dts/mediatek,mt7621-rfb.dts | 68 + arch/mips/dts/mt7621.dtsi | 372 ++++++ arch/mips/mach-mtmips/Kconfig | 34 +- arch/mips/mach-mtmips/Makefile | 5 + arch/mips/mach-mtmips/cpu.c | 2 +- arch/mips/mach-mtmips/mt7621/Kconfig | 43 + arch/mips/mach-mtmips/mt7621/Makefile | 5 + arch/mips/mach-mtmips/mt7621/compat.c | 21 + arch/mips/mach-mtmips/mt7621/init.c | 156 +++ arch/mips/mach-mtmips/mt7621/mt7621.h | 204 +++ arch/mips/mach-mtmips/mt7621/serial.c | 23 + board/mediatek/mt7621/MAINTAINERS | 9 + board/mediatek/mt7621/Makefile | 3 + board/mediatek/mt7621/board.c | 6 + configs/mt7621_nand_rfb_ramboot_defconfig | 72 + configs/mt7621_rfb_ramboot_defconfig | 75 ++ drivers/clk/mtmips/Makefile | 1 + drivers/clk/mtmips/clk-mt7621.c | 260 ++++ drivers/gpio/Kconfig | 2 +- drivers/mmc/mtk-sd.c | 13 + drivers/mtd/nand/raw/Kconfig | 11 + drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/mt7621_nand.c | 1189 +++++++++++++++++ drivers/net/mtk_eth.c | 27 +- drivers/net/mtk_eth.h | 8 + drivers/phy/Kconfig | 2 +- drivers/pinctrl/mtmips/Kconfig | 9 + drivers/pinctrl/mtmips/Makefile | 1 + drivers/pinctrl/mtmips/pinctrl-mt7621.c | 307 +++++ .../pinctrl/mtmips/pinctrl-mtmips-common.c | 4 +- .../pinctrl/mtmips/pinctrl-mtmips-common.h | 12 + drivers/spi/Kconfig | 2 +- drivers/usb/host/Kconfig | 2 +- drivers/watchdog/Kconfig | 2 +- include/configs/mt7621-rfb.h | 18 + include/configs/mt7621.h | 36 + include/dt-bindings/clock/mt7621-clk.h | 42 + include/dt-bindings/reset/mt7621-reset.h | 38 + 41 files changed, 3126 insertions(+), 18 deletions(-) create mode 100644 arch/mips/dts/mediatek,mt7621-nand-rfb.dts create mode 100644 arch/mips/dts/mediatek,mt7621-rfb.dts create mode 100644 arch/mips/dts/mt7621.dtsi create mode 100644 arch/mips/mach-mtmips/mt7621/Kconfig create mode 100644 arch/mips/mach-mtmips/mt7621/Makefile create mode 100644 arch/mips/mach-mtmips/mt7621/compat.c create mode 100644 arch/mips/mach-mtmips/mt7621/init.c create mode 100644 arch/mips/mach-mtmips/mt7621/mt7621.h create mode 100644 arch/mips/mach-mtmips/mt7621/serial.c create mode 100644 board/mediatek/mt7621/MAINTAINERS create mode 100644 board/mediatek/mt7621/Makefile create mode 100644 board/mediatek/mt7621/board.c create mode 100644 configs/mt7621_nand_rfb_ramboot_defconfig create mode 100644 configs/mt7621_rfb_ramboot_defconfig create mode 100644 drivers/clk/mtmips/clk-mt7621.c create mode 100644 drivers/mtd/nand/raw/mt7621_nand.c create mode 100644 drivers/pinctrl/mtmips/pinctrl-mt7621.c create mode 100644 include/configs/mt7621-rfb.h create mode 100644 include/configs/mt7621.h create mode 100644 include/dt-bindings/clock/mt7621-clk.h create mode 100644 include/dt-bindings/reset/mt7621-reset.h

This patch adds support for MediaTek MT7621 SoC. All files are dedicated for u-boot.
Currently only ramboot is supported. The default build target is u-boot-lzma.img. This file can be booted using bootm command, or be used as a payload of the SDK preloader of MT7621.
The specification of this chip: https://www.mediatek.com/products/homenetworking/mt7621
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: Add a kconfig for max supported ram size Remove network configs from default config file --- arch/mips/dts/mt7621.dtsi | 372 ++++++++++++++++++++++++++ arch/mips/mach-mtmips/Kconfig | 34 ++- arch/mips/mach-mtmips/Makefile | 5 + arch/mips/mach-mtmips/cpu.c | 2 +- arch/mips/mach-mtmips/mt7621/Kconfig | 23 ++ arch/mips/mach-mtmips/mt7621/Makefile | 5 + arch/mips/mach-mtmips/mt7621/compat.c | 21 ++ arch/mips/mach-mtmips/mt7621/init.c | 156 +++++++++++ arch/mips/mach-mtmips/mt7621/mt7621.h | 204 ++++++++++++++ arch/mips/mach-mtmips/mt7621/serial.c | 23 ++ include/configs/mt7621.h | 36 +++ 11 files changed, 876 insertions(+), 5 deletions(-) create mode 100644 arch/mips/dts/mt7621.dtsi create mode 100644 arch/mips/mach-mtmips/mt7621/Kconfig create mode 100644 arch/mips/mach-mtmips/mt7621/Makefile create mode 100644 arch/mips/mach-mtmips/mt7621/compat.c create mode 100644 arch/mips/mach-mtmips/mt7621/init.c create mode 100644 arch/mips/mach-mtmips/mt7621/mt7621.h create mode 100644 arch/mips/mach-mtmips/mt7621/serial.c create mode 100644 include/configs/mt7621.h
diff --git a/arch/mips/dts/mt7621.dtsi b/arch/mips/dts/mt7621.dtsi new file mode 100644 index 0000000000..c09350b370 --- /dev/null +++ b/arch/mips/dts/mt7621.dtsi @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 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 = <0>; + }; + }; + + clk48m: clk48m@0 { + compatible = "fixed-clock"; + + clock-frequency = <48000000>; + + #clock-cells = <0>; + }; + + clk50m: clk50m@0 { + compatible = "fixed-clock"; + + clock-frequency = <50000000>; + + #clock-cells = <0>; + }; + + sysc: sysc@1e000000 { + compatible = "mediatek,mt7621-sysc", "syscon"; + reg = <0x1e000000 0x100>; + }; + + clkctrl: clkctrl@1e000030 { + compatible = "mediatek,mt7621-clk"; + mediatek,sysc = <&sysc>; + mediatek,memc = <&memc>; + + #clock-cells = <1>; + u-boot,dm-pre-reloc; + }; + + rstctrl: rstctrl@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: memc@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 { + groups = "uart1"; + function = "uart"; + }; + + gpios { + groups = "i2c", "uart3", "pcie reset"; + function = "gpio"; + }; + + jtag { + groups = "jtag"; + function = "jtag"; + }; + + wdt { + groups = "wdt"; + function = "wdt rst"; + }; + }; + + 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 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 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 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 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 CLK_GMAC>, + <&clkctrl CLK_FE>; + 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 CLK_SDXC>; + 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"; + + /* power-domains = <&scpsys MT7629_POWER_DOMAIN_HIF1>; */ + + clocks = <&clk48m>, <&clk48m>; + clock-names = "sys_ck", "ref_ck"; + + phys = <&u2port0 PHY_TYPE_USB2>, + <&u3port0 PHY_TYPE_USB3>, + <&u2port1 PHY_TYPE_USB2>; + + status = "disabled"; + }; + + u3phy: usb-phy@1e1d0000 { + compatible = "mediatek,mt7621-u3phy", + "mediatek,generic-tphy-v1"; + reg = <0x1e1d0000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + status = "disabled"; + + u2port0: usb-phy@1e1d0800 { + reg = <0x1e1d0800 0x0100>; + #phy-cells = <1>; + clocks = <&clk48m>; + clock-names = "ref"; + }; + + u3port0: usb-phy@1e1d0900 { + reg = <0x1e1d0900 0x0100>; + #phy-cells = <1>; + }; + + u2port1: usb-phy@1e1d1000 { + reg = <0x1e1d1000 0x0100>; + #phy-cells = <1>; + clocks = <&clk48m>; + clock-names = "ref"; + }; + }; + + i2c: i2c@1e000900 { + compatible = "i2c-gpio"; + + status = "disabled"; + + i2c-gpio,delay-us = <3>; + + gpios = <&gpio0 3 1>, /* PIN3 as SDA */ + <&gpio0 4 1>; /* PIN4 as CLK */ + + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/mips/mach-mtmips/Kconfig b/arch/mips/mach-mtmips/Kconfig index 151b004603..a73e9f8bd8 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,36 @@ 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_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 TPL_TEXT_BASE + default 0xbfc00000 if SOC_MT7621
config SPL_PAYLOAD default "u-boot-lzma.img" if SPL_LZMA
config BUILD_TARGET + default "u-boot-lzma.img" if SOC_MT7621 # Only ramboot is supported now default "u-boot-with-spl.bin" if SPL 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 +67,19 @@ 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 + help + This supports MediaTek MT7621. + config SOC_MT7628 bool "MT7628" select SYS_CACHE_SHIFT_5 @@ -80,6 +105,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 4909b47ef2..9ab882dee0 100644 --- a/arch/mips/mach-mtmips/Makefile +++ b/arch/mips/mach-mtmips/Makefile @@ -1,9 +1,14 @@ # 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 +endif + obj-$(CONFIG_SPL_BUILD) += spl.o
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 a4b5cff61d..f1e9022738 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 0000000000..6948bee31b --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/Kconfig @@ -0,0 +1,23 @@ + +if SOC_MT7621 + +config DEBUG_UART_BOARD_INIT + default y + +choice + prompt "Board select" + +endchoice + +config SYS_CONFIG_NAME + string "Board configuration name" + default "mt7621" if BOARD_MT7621_RFB || BOARD_MT7621_NAND_RFB + +config SYS_BOARD + string "Board name" + default "mt7621" if BOARD_MT7621_RFB || BOARD_MT7621_NAND_RFB + +config SYS_VENDOR + default "mediatek" if BOARD_MT7621_RFB || BOARD_MT7621_NAND_RFB + +endif diff --git a/arch/mips/mach-mtmips/mt7621/Makefile b/arch/mips/mach-mtmips/mt7621/Makefile new file mode 100644 index 0000000000..adb48ffe37 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-y += init.o +obj-y += serial.o +obj-y += compat.o diff --git a/arch/mips/mach-mtmips/mt7621/compat.c b/arch/mips/mach-mtmips/mt7621/compat.c new file mode 100644 index 0000000000..ae2dd263f7 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/compat.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao weijie.gao@mediatek.com + */ + +#include <malloc.h> +#include <asm/io.h> +#include <asm/addrspace.h> + +/* This is used for the mtk-eth driver */ +phys_addr_t noncached_alloc(size_t size, size_t align) +{ + void *ptr = memalign(align, ALIGN(size, align)); + + if (!ptr) + return 0; + + return KSEG1ADDR((ulong)ptr); +} diff --git a/arch/mips/mach-mtmips/mt7621/init.c b/arch/mips/mach-mtmips/mt7621/init.c new file mode 100644 index 0000000000..ca72d37980 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/init.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 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 "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 cpu_clk, ddr_clk, bus_clk, xtal_clk, timer_freq; + u32 val, ver, eco, pkg, core, dram, chipmode; + struct udevice *clkdev; + const char *bootdev; + struct clk clk; + int ret; + + val = readl(sysc + SYSCTL_CHIP_REV_ID_REG); + ver = (val & VER_ID_M) >> VER_ID_S; + eco = (val & ECO_ID_M) >> ECO_ID_S; + pkg = !!(val & PKG_ID); + core = !!(val & CPU_ID); + + val = readl(sysc + SYSCTL_SYSCFG0_REG); + dram = val & DRAM_TYPE; + chipmode = (val & CHIP_MODE_M) >> CHIP_MODE_S; + + 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 = CLK_CPU; + cpu_clk = clk_get_rate(&clk); + + clk.id = CLK_SYS; + bus_clk = clk_get_rate(&clk); + + clk.id = CLK_DDR; + ddr_clk = clk_get_rate(&clk); + + clk.id = CLK_XTAL; + xtal_clk = clk_get_rate(&clk); + + clk.id = CLK_MIPS_CNT; + timer_freq = clk_get_rate(&clk); + + /* Set final timer frequency */ + if (timer_freq) + gd->arch.timer_freq = timer_freq; + + 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; +} + +void lowlevel_init(void) +{ + void __iomem *usbh = ioremap_nocache(SSUSB_BASE, SSUSB_SIZE); + + /* Setup USB xHCI */ + + writel((0x20 << SSUSB_MAC3_SYS_CK_GATE_MASK_TIME_S) | + (0x20 << SSUSB_MAC2_SYS_CK_GATE_MASK_TIME_S) | + (2 << SSUSB_MAC3_SYS_CK_GATE_MODE_S) | + (2 << SSUSB_MAC2_SYS_CK_GATE_MODE_S) | 0x10, + usbh + SSUSB_MAC_CK_CTRL_REG); + + writel((2 << SSUSB_PLL_PREDIV_PE1D_S) | (1 << SSUSB_PLL_PREDIV_U3_S) | + (4 << SSUSB_PLL_FBKDI_S), usbh + DA_SSUSB_U3PHYA_10_REG); + + writel((0x18 << SSUSB_PLL_FBKDIV_PE2H_S) | + (0x18 << SSUSB_PLL_FBKDIV_PE1D_S) | + (0x18 << SSUSB_PLL_FBKDIV_PE1H_S) | + (0x1e << SSUSB_PLL_FBKDIV_U3_S), + usbh + DA_SSUSB_PLL_FBKDIV_REG); + + writel((0x1e400000 << SSUSB_PLL_PCW_NCPO_U3_S), + usbh + DA_SSUSB_PLL_PCW_NCPO_REG); + + writel((0x25 << SSUSB_PLL_SSC_DELTA1_PE1H_S) | + (0x73 << SSUSB_PLL_SSC_DELTA1_U3_S), + usbh + DA_SSUSB_PLL_SSC_DELTA1_REG); + + writel((0x71 << SSUSB_PLL_SSC_DELTA_U3_S) | + (0x4a << SSUSB_PLL_SSC_DELTA1_PE2D_S), + usbh + DA_SSUSB_U3PHYA_21_REG); + + writel((0x140 << SSUSB_PLL_SSC_PRD_S), usbh + SSUSB_U3PHYA_9_REG); + + writel((0x11c00000 << SSUSB_SYSPLL_PCW_NCPO_S), + usbh + SSUSB_U3PHYA_3_REG); + + writel((4 << SSUSB_PCIE_CLKDRV_AMP_S) | (1 << SSUSB_SYSPLL_FBSEL_S) | + (1 << SSUSB_SYSPLL_PREDIV_S), usbh + SSUSB_U3PHYA_1_REG); + + writel((0x12 << SSUSB_SYSPLL_FBDIV_S) | 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 | (8 << SSUSB_RX_DAC_MUX_S) | + (1 << SSUSB_PCIE_SIGDET_VTH_S) | (1 << SSUSB_PCIE_SIGDET_LPF_S), + usbh + SSUSB_U3PHYA_11_REG); + + writel((0x1ff << SSUSB_RING_OSC_CNTEND_S) | + (0x7f << SSUSB_XTAL_OSC_CNTEND_S) | SSUSB_RING_BYPASS_DET, + usbh + SSUSB_B2_ROSC_0_REG); + + writel((3 << SSUSB_RING_OSC_FRC_RECAL_S) | SSUSB_RING_OSC_FRC_SEL, + usbh + SSUSB_B2_ROSC_1_REG); +} + +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 0000000000..012f5a3557 --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/mt7621.h @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 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 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 + +/* 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 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 + +#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 0000000000..393188abce --- /dev/null +++ b/arch/mips/mach-mtmips/mt7621/serial.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. + * + * 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/include/configs/mt7621.h b/include/configs/mt7621.h new file mode 100644 index 0000000000..c3da1ad423 --- /dev/null +++ b/include/configs/mt7621.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao weijie.gao@mediatek.com + */ + +#ifndef __CONFIG_MT7621_H +#define __CONFIG_MT7621_H + +#define CONFIG_SYS_HZ 1000 +#define CONFIG_SYS_MIPS_TIMER_FREQ 440000000 + +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE + +#define CONFIG_SYS_BOOTPARAMS_LEN 0x20000 + +#define CONFIG_SYS_SDRAM_BASE 0x80000000 + +#define CONFIG_VERY_BIG_RAM +#define CONFIG_MAX_MEM_MAPPED 0x1c000000 + +#define CONFIG_SYS_INIT_SP_OFFSET 0x80000 + +#define CONFIG_SYS_BOOTM_LEN 0x2000000 + +#define CONFIG_SYS_MAXARGS 16 +#define CONFIG_SYS_CBSIZE 1024 + +/* MMC */ +#define MMC_SUPPORTS_TUNING + +/* NAND */ +#define CONFIG_SYS_MAX_NAND_DEVICE 1 + +#endif /* __CONFIG_MT7621_H */

The mt7621_rfb board supports integrated giga PHYs plus one external giga PHYs. It also has up to 512MiB DDR3, 16MB SPI-NOR, 3 mini PCI-e x1 slots, SDXC and USB.
The mt7621_nand_rfb board is almost the same as mt7621_rfb board, but it uses NAND flash and SDXC is not available.
Reviewed-by: Daniel Schwierzeck daniel.schwierzeck@gmail.com Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: Add config file for mt7621-rfb boards --- arch/mips/dts/Makefile | 2 + arch/mips/dts/mediatek,mt7621-nand-rfb.dts | 52 +++++++++++++++ arch/mips/dts/mediatek,mt7621-rfb.dts | 68 ++++++++++++++++++++ arch/mips/mach-mtmips/mt7621/Kconfig | 20 ++++++ board/mediatek/mt7621/MAINTAINERS | 9 +++ board/mediatek/mt7621/Makefile | 3 + board/mediatek/mt7621/board.c | 6 ++ configs/mt7621_nand_rfb_ramboot_defconfig | 72 +++++++++++++++++++++ configs/mt7621_rfb_ramboot_defconfig | 75 ++++++++++++++++++++++ include/configs/mt7621-rfb.h | 18 ++++++ 10 files changed, 325 insertions(+) create mode 100644 arch/mips/dts/mediatek,mt7621-nand-rfb.dts create mode 100644 arch/mips/dts/mediatek,mt7621-rfb.dts create mode 100644 board/mediatek/mt7621/MAINTAINERS create mode 100644 board/mediatek/mt7621/Makefile create mode 100644 board/mediatek/mt7621/board.c create mode 100644 configs/mt7621_nand_rfb_ramboot_defconfig create mode 100644 configs/mt7621_rfb_ramboot_defconfig create mode 100644 include/configs/mt7621-rfb.h
diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile index 215283cfa0..1ef5a28e93 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 0000000000..80870fe3f3 --- /dev/null +++ b/arch/mips/dts/mediatek,mt7621-nand-rfb.dts @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 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"; + }; + }; +}; + +&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 0000000000..c8561548f5 --- /dev/null +++ b/arch/mips/dts/mediatek,mt7621-rfb.dts @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 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 { + }; +}; + +&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/mach-mtmips/mt7621/Kconfig b/arch/mips/mach-mtmips/mt7621/Kconfig index 6948bee31b..add1f4154b 100644 --- a/arch/mips/mach-mtmips/mt7621/Kconfig +++ b/arch/mips/mach-mtmips/mt7621/Kconfig @@ -7,6 +7,26 @@ config DEBUG_UART_BOARD_INIT 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 diff --git a/board/mediatek/mt7621/MAINTAINERS b/board/mediatek/mt7621/MAINTAINERS new file mode 100644 index 0000000000..add653b931 --- /dev/null +++ b/board/mediatek/mt7621/MAINTAINERS @@ -0,0 +1,9 @@ +MT7621_RFB BOARD +M: Weijie Gao weijie.gao@mediatek.com +S: Maintained +F: board/mediatek/mt7621 +F: configs/mt7621_rfb_ramboot_defconfig +F: configs/mt7621_nand_rfb_ramboot_defconfig +F: arch/mips/dts/mediatek,mt7621-rfb.dts +F: arch/mips/dts/mediatek,mt7621-nand-rfb.dts +F: include/configs/mt7621-rfb.h diff --git a/board/mediatek/mt7621/Makefile b/board/mediatek/mt7621/Makefile new file mode 100644 index 0000000000..db129c5aba --- /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 0000000000..119b8fc9e5 --- /dev/null +++ b/board/mediatek/mt7621/board.c @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao weijie.gao@mediatek.com + */ diff --git a/configs/mt7621_nand_rfb_ramboot_defconfig b/configs/mt7621_nand_rfb_ramboot_defconfig new file mode 100644 index 0000000000..f5088ca629 --- /dev/null +++ b/configs/mt7621_nand_rfb_ramboot_defconfig @@ -0,0 +1,72 @@ +CONFIG_MIPS=y +CONFIG_SYS_CONFIG_NAME="mt7621-rfb" +CONFIG_NR_DRAM_BANKS=1 +CONFIG_ENV_SIZE=0x1000 +CONFIG_SYS_MALLOC_LEN=0x100000 +CONFIG_DEFAULT_DEVICE_TREE="mediatek,mt7621-nand-rfb" +CONFIG_DEBUG_UART_BASE=0xbe000c00 +CONFIG_DEBUG_UART_CLOCK=50000000 +CONFIG_ARCH_MTMIPS=y +CONFIG_SOC_MT7621=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_SPL_INIT_STACK_WITHOUT_MALLOC_F=y +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEBUG_UART=y +CONFIG_SYS_LOAD_ADDR=0x83000000 +CONFIG_FIT=y +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set +CONFIG_SYS_CONSOLE_INFO_QUIET=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_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_ISO_PARTITION is not set +CONFIG_EFI_PARTITION=y +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_MEDIATEK_ETH=y +CONFIG_PHY=y +CONFIG_PHY_MTK_TPHY=y +CONFIG_SPECIFY_CONSOLE_INDEX=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_LZMA=y +CONFIG_SPL_LZMA=y diff --git a/configs/mt7621_rfb_ramboot_defconfig b/configs/mt7621_rfb_ramboot_defconfig new file mode 100644 index 0000000000..6f6bb52c9e --- /dev/null +++ b/configs/mt7621_rfb_ramboot_defconfig @@ -0,0 +1,75 @@ +CONFIG_MIPS=y +CONFIG_SYS_CONFIG_NAME="mt7621-rfb" +CONFIG_NR_DRAM_BANKS=1 +CONFIG_ENV_SIZE=0x1000 +CONFIG_SYS_MALLOC_LEN=0x100000 +CONFIG_DEFAULT_DEVICE_TREE="mediatek,mt7621-rfb" +CONFIG_DEBUG_UART_BASE=0xbe000c00 +CONFIG_DEBUG_UART_CLOCK=50000000 +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_SPL_INIT_STACK_WITHOUT_MALLOC_F=y +CONFIG_MIPS_BOOT_FDT=y +CONFIG_DEBUG_UART=y +CONFIG_SYS_LOAD_ADDR=0x83000000 +CONFIG_FIT=y +# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set +CONFIG_SYS_CONSOLE_INFO_QUIET=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_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_USB=y +# CONFIG_CMD_NFS is not set +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +# CONFIG_ISO_PARTITION is not set +CONFIG_EFI_PARTITION=y +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_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_MEDIATEK_ETH=y +CONFIG_PHY=y +CONFIG_PHY_MTK_TPHY=y +CONFIG_SPECIFY_CONSOLE_INDEX=y +CONFIG_DEBUG_UART_SHIFT=2 +CONFIG_SPI=y +CONFIG_MT7621_SPI=y +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_LZMA=y +CONFIG_SPL_LZMA=y diff --git a/include/configs/mt7621-rfb.h b/include/configs/mt7621-rfb.h new file mode 100644 index 0000000000..2287cb1103 --- /dev/null +++ b/include/configs/mt7621-rfb.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao weijie.gao@mediatek.com + */ + +#ifndef __CONFIG_MT7621_RFB_H +#define __CONFIG_MT7621_RFB_H + +#include "mt7621.h" + +/* Network */ +#define CONFIG_IPADDR 192.168.1.1 +#define CONFIG_SERVERIP 192.168.1.2 +#define CONFIG_NETMASK 255.255.255.0 + +#endif /* __CONFIG_MT7621_RFB_H */

This patch adds a clock driver for MediaTek MT7621 SoC. This driver provides clock gate control as well as getting clock frequency for CPU/SYS/XTAL and some peripherals.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/clk/mtmips/Makefile | 1 + drivers/clk/mtmips/clk-mt7621.c | 260 +++++++++++++++++++++++++ include/dt-bindings/clock/mt7621-clk.h | 42 ++++ 3 files changed, 303 insertions(+) create mode 100644 drivers/clk/mtmips/clk-mt7621.c create mode 100644 include/dt-bindings/clock/mt7621-clk.h
diff --git a/drivers/clk/mtmips/Makefile b/drivers/clk/mtmips/Makefile index 732e7f2545..ee8b5afe87 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 0000000000..3799d1806a --- /dev/null +++ b/drivers/clk/mtmips/clk-mt7621.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao weijie.gao@mediatek.com + */ + +#include <common.h> +#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/bitops.h> +#include <linux/io.h> + +#define SYSC_MAP_SIZE 0x100 +#define MEMC_MAP_SIZE 0x1000 + +/* SYSC */ +#define SYSCFG0_REG 0x10 +#define XTAL_MODE_SEL_S 6 +#define XTAL_MODE_SEL_M 0x1c0 + +#define CLKCFG0_REG 0x2c +#define CPU_CLK_SEL_S 30 +#define CPU_CLK_SEL_M 0xc0000000 +#define PERI_CLK_SEL 0x10 + +#define CLKCFG1_REG 0x30 + +#define 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 + +/* MEMC */ +#define MEMPLL1_REG 0x0604 +#define RG_MEPL_DIV2_SEL_S 1 +#define RG_MEPL_DIV2_SEL_M 0x06 + +#define MEMPLL6_REG 0x0618 +#define MEMPLL18_REG 0x0648 +#define RG_MEPL_PREDIV_S 12 +#define RG_MEPL_PREDIV_M 0x3000 +#define RG_MEPL_FBDIV_S 4 +#define RG_MEPL_FBDIV_M 0x7f0 + +/* Clock sources */ +#define CLK_SRC_CPU -1 +#define CLK_SRC_CPU_D2 -2 +#define CLK_SRC_DDR -3 +#define CLK_SRC_SYS -4 +#define CLK_SRC_XTAL -5 +#define CLK_SRC_PERI -6 + +/* EPLL clock */ +#define EPLL_CLK 50000000 + +struct mt7621_clk_priv { + void __iomem *sysc_base; + void __iomem *memc_base; + int cpu_clk; + int ddr_clk; + int sys_clk; + int xtal_clk; +}; + +static const int mt7621_clks[] = { + [CLK_SYS] = CLK_SRC_SYS, + [CLK_DDR] = CLK_SRC_DDR, + [CLK_CPU] = CLK_SRC_CPU, + [CLK_XTAL] = CLK_SRC_XTAL, + [CLK_MIPS_CNT] = CLK_SRC_CPU_D2, + [CLK_UART3] = CLK_SRC_PERI, + [CLK_UART2] = CLK_SRC_PERI, + [CLK_UART1] = CLK_SRC_PERI, + [CLK_SPI] = CLK_SRC_SYS, + [CLK_I2C] = CLK_SRC_PERI, + [CLK_TIMER] = CLK_SRC_PERI, +}; + +static ulong mt7621_clk_get_rate(struct clk *clk) +{ + struct mt7621_clk_priv *priv = dev_get_priv(clk->dev); + u32 val; + + if (clk->id >= ARRAY_SIZE(mt7621_clks)) + return 0; + + switch (mt7621_clks[clk->id]) { + case CLK_SRC_CPU: + return priv->cpu_clk; + case CLK_SRC_CPU_D2: + return priv->cpu_clk / 2; + 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 EPLL_CLK; + default: + return 0; + } +} + +static int mt7621_clk_enable(struct clk *clk) +{ + struct mt7621_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id > 31) + return -1; + + setbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk->id)); + + return 0; +} + +static int mt7621_clk_disable(struct clk *clk) +{ + struct mt7621_clk_priv *priv = dev_get_priv(clk->dev); + + if (clk->id > 31) + return -1; + + clrbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk->id)); + + return 0; +} + +const struct clk_ops mt7621_clk_ops = { + .enable = mt7621_clk_enable, + .disable = mt7621_clk_disable, + .get_rate = mt7621_clk_get_rate, +}; + +static void mt7621_get_clocks(struct mt7621_clk_priv *priv) +{ + 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 = (bs & XTAL_MODE_SEL_M) >> XTAL_MODE_SEL_S; + + 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 ((clkcfg0 & CPU_CLK_SEL_M) >> CPU_CLK_SEL_S) { + case 0: + cpu_clk = 500 * 1000 * 1000; + break; + case 1: + mempll = readl(priv->memc_base + MEMPLL18_REG); + dividx = (mempll & RG_MEPL_PREDIV_M) >> RG_MEPL_PREDIV_S; + fb = (mempll & RG_MEPL_FBDIV_M) >> RG_MEPL_FBDIV_S; + xtal_div = 1 << xtal_div_tbl[dividx]; + cpu_clk = (fb + 1) * xtal_clk / xtal_div; + break; + default: + cpu_clk = xtal_clk; + } + + ffiv = (cur_clk & CUR_CPU_FDIV_M) >> CUR_CPU_FDIV_S; + ffrac = (cur_clk & CUR_CPU_FFRAC_M) >> CUR_CPU_FFRAC_S; + cpu_clk = cpu_clk / ffiv * ffrac; + + mempll = readl(priv->memc_base + MEMPLL6_REG); + dividx = (mempll & RG_MEPL_PREDIV_M) >> RG_MEPL_PREDIV_S; + fb = (mempll & RG_MEPL_FBDIV_M) >> RG_MEPL_FBDIV_S; + xtal_div = 1 << xtal_div_tbl[dividx]; + ddr_clk = fb * xtal_clk / xtal_div; + + bs = readl(priv->memc_base + MEMPLL1_REG); + if (((bs & RG_MEPL_DIV2_SEL_M) >> RG_MEPL_DIV2_SEL_S) == 0) + 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 regmap *regmap; + void __iomem *base; + int ret; + + /* get corresponding sysc phandle */ + ret = dev_read_phandle_with_args(dev, "mediatek,sysc", NULL, 0, 0, + &args); + if (ret) + return ret; + + regmap = syscon_node_to_regmap(args.node); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + base = regmap_get_range(regmap, 0); + if (!base) { + dev_err(dev, "Unable to find sysc\n"); + return -ENODEV; + } + + priv->sysc_base = ioremap_nocache((phys_addr_t)base, SYSC_MAP_SIZE); + + /* get corresponding memc phandle */ + ret = dev_read_phandle_with_args(dev, "mediatek,memc", NULL, 0, 0, + &args); + if (ret) + return ret; + + regmap = syscon_node_to_regmap(args.node); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + base = regmap_get_range(regmap, 0); + if (!base) { + dev_err(dev, "Unable to find memc\n"); + return -ENODEV; + } + + priv->memc_base = ioremap_nocache((phys_addr_t)base, MEMC_MAP_SIZE); + + mt7621_get_clocks(priv); + + 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/include/dt-bindings/clock/mt7621-clk.h b/include/dt-bindings/clock/mt7621-clk.h new file mode 100644 index 0000000000..b24aef351c --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 MediaTek Inc. All rights reserved. + * + * Author: Weijie Gao weijie.gao@mediatek.com + */ + +#ifndef _DT_BINDINGS_MT7621_CLK_H_ +#define _DT_BINDINGS_MT7621_CLK_H_ + +/* Base clocks */ +#define CLK_MIPS_CNT 36 +#define CLK_SYS 35 +#define CLK_DDR 34 +#define CLK_CPU 33 +#define CLK_XTAL 32 + +/* Peripheral clocks */ +#define CLK_SDXC 30 +#define CLK_CRYPTO 29 +#define CLK_PCIE2 26 +#define CLK_PCIE1 25 +#define CLK_PCIE0 24 +#define CLK_GMAC 23 +#define CLK_UART3 21 +#define CLK_UART2 20 +#define CLK_UART1 19 +#define CLK_SPI 18 +#define CLK_I2S 17 +#define CLK_I2C 16 +#define CLK_NFI 15 +#define CLK_GDMA 14 +#define CLK_PIO 13 +#define CLK_PCM 11 +#define CLK_MC 10 +#define CLK_INTC 9 +#define CLK_TIMER 8 +#define CLK_SPDIFTX 7 +#define CLK_FE 6 +#define CLK_HSDMA 5 + +#endif /* _DT_BINDINGS_MT7621_CLK_H_ */

On 11/18/21 8:35 PM, Weijie Gao wrote:
This patch adds a clock driver for MediaTek MT7621 SoC. This driver provides clock gate control as well as getting clock frequency for CPU/SYS/XTAL and some peripherals.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
v2 changes: none
drivers/clk/mtmips/Makefile | 1 + drivers/clk/mtmips/clk-mt7621.c | 260 +++++++++++++++++++++++++ include/dt-bindings/clock/mt7621-clk.h | 42 ++++ 3 files changed, 303 insertions(+) create mode 100644 drivers/clk/mtmips/clk-mt7621.c create mode 100644 include/dt-bindings/clock/mt7621-clk.h
diff --git a/drivers/clk/mtmips/Makefile b/drivers/clk/mtmips/Makefile index 732e7f2545..ee8b5afe87 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 0000000000..3799d1806a --- /dev/null +++ b/drivers/clk/mtmips/clk-mt7621.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2021 MediaTek Inc. All Rights Reserved.
- Author: Weijie Gao weijie.gao@mediatek.com
- */
+#include <common.h> +#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/bitops.h> +#include <linux/io.h>
+#define SYSC_MAP_SIZE 0x100 +#define MEMC_MAP_SIZE 0x1000
+/* SYSC */ +#define SYSCFG0_REG 0x10 +#define XTAL_MODE_SEL_S 6 +#define XTAL_MODE_SEL_M 0x1c0
Please use genmask to define this:
#define XTAL_MODE_SEL_M GENMASK(8, 6)
and SEL_S is unnecessary, see commentary below.
+#define CLKCFG0_REG 0x2c +#define CPU_CLK_SEL_S 30 +#define CPU_CLK_SEL_M 0xc0000000 +#define PERI_CLK_SEL 0x10
+#define CLKCFG1_REG 0x30
+#define 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
+/* MEMC */ +#define MEMPLL1_REG 0x0604 +#define RG_MEPL_DIV2_SEL_S 1 +#define RG_MEPL_DIV2_SEL_M 0x06
+#define MEMPLL6_REG 0x0618 +#define MEMPLL18_REG 0x0648 +#define RG_MEPL_PREDIV_S 12 +#define RG_MEPL_PREDIV_M 0x3000 +#define RG_MEPL_FBDIV_S 4 +#define RG_MEPL_FBDIV_M 0x7f0
+/* Clock sources */ +#define CLK_SRC_CPU -1 +#define CLK_SRC_CPU_D2 -2 +#define CLK_SRC_DDR -3 +#define CLK_SRC_SYS -4 +#define CLK_SRC_XTAL -5 +#define CLK_SRC_PERI -6
Please use an enum. And why are these negative?
+/* EPLL clock */ +#define EPLL_CLK 50000000
+struct mt7621_clk_priv {
- void __iomem *sysc_base;
- void __iomem *memc_base;
- int cpu_clk;
- int ddr_clk;
- int sys_clk;
- int xtal_clk;
+};
+static const int mt7621_clks[] = {
- [CLK_SYS] = CLK_SRC_SYS,
- [CLK_DDR] = CLK_SRC_DDR,
- [CLK_CPU] = CLK_SRC_CPU,
- [CLK_XTAL] = CLK_SRC_XTAL,
- [CLK_MIPS_CNT] = CLK_SRC_CPU_D2,
- [CLK_UART3] = CLK_SRC_PERI,
- [CLK_UART2] = CLK_SRC_PERI,
- [CLK_UART1] = CLK_SRC_PERI,
- [CLK_SPI] = CLK_SRC_SYS,
- [CLK_I2C] = CLK_SRC_PERI,
- [CLK_TIMER] = CLK_SRC_PERI,
+};
+static ulong mt7621_clk_get_rate(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- u32 val;
- if (clk->id >= ARRAY_SIZE(mt7621_clks))
return 0;
- switch (mt7621_clks[clk->id]) {
- case CLK_SRC_CPU:
return priv->cpu_clk;
- case CLK_SRC_CPU_D2:
return priv->cpu_clk / 2;
- 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 EPLL_CLK;
- default:
return 0;
-ENOSYS
- }
+}
+static int mt7621_clk_enable(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- if (clk->id > 31)
Please compare with a symbol.
return -1;
-ENOSYS
- setbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk->id));
- return 0;
+}
+static int mt7621_clk_disable(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- if (clk->id > 31)
return -1;
- clrbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk->id));
- return 0;
+}
+const struct clk_ops mt7621_clk_ops = {
- .enable = mt7621_clk_enable,
- .disable = mt7621_clk_disable,
- .get_rate = mt7621_clk_get_rate,
+};
+static void mt7621_get_clocks(struct mt7621_clk_priv *priv) +{
- 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 = (bs & XTAL_MODE_SEL_M) >> XTAL_MODE_SEL_S;
xtal_sel = FIELD_GET(XTAL_MODE_SEL_M, 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 ((clkcfg0 & CPU_CLK_SEL_M) >> CPU_CLK_SEL_S) {
ditto
- case 0:
cpu_clk = 500 * 1000 * 1000;
break;
- case 1:
mempll = readl(priv->memc_base + MEMPLL18_REG);
dividx = (mempll & RG_MEPL_PREDIV_M) >> RG_MEPL_PREDIV_S;
fb = (mempll & RG_MEPL_FBDIV_M) >> RG_MEPL_FBDIV_S;
ditto
xtal_div = 1 << xtal_div_tbl[dividx];
cpu_clk = (fb + 1) * xtal_clk / xtal_div;
break;
- default:
cpu_clk = xtal_clk;
- }
- ffiv = (cur_clk & CUR_CPU_FDIV_M) >> CUR_CPU_FDIV_S;
- ffrac = (cur_clk & CUR_CPU_FFRAC_M) >> CUR_CPU_FFRAC_S;
ditto
- cpu_clk = cpu_clk / ffiv * ffrac;
- mempll = readl(priv->memc_base + MEMPLL6_REG);
- dividx = (mempll & RG_MEPL_PREDIV_M) >> RG_MEPL_PREDIV_S;
- fb = (mempll & RG_MEPL_FBDIV_M) >> RG_MEPL_FBDIV_S;
ditto
- xtal_div = 1 << xtal_div_tbl[dividx];
- ddr_clk = fb * xtal_clk / xtal_div;
- bs = readl(priv->memc_base + MEMPLL1_REG);
- if (((bs & RG_MEPL_DIV2_SEL_M) >> RG_MEPL_DIV2_SEL_S) == 0)
ditto
and you can just use
if (!cond)
ddr_clk *= 2;
- priv->cpu_clk = cpu_clk;
- priv->sys_clk = cpu_clk / 4;
- priv->ddr_clk = ddr_clk;
- priv->xtal_clk = xtal_clk;
Please implement the above logic in get_rate(). For example:
static ulong do_mt7621_clk_get_rate() { ... switch (clk->id) { case CLK_SYS: cpu_clk = do_mt7621_clk_get_rate(priv, CLK_SYS); return IS_ERROR_VALUE(cpu_clk) ? cpu_clk : cpu_clk / 4; ... } }
static ulong mt7621_clk_get_rate() { struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
return do_mt7621_clk_get_rate(priv, clk->id); }
+}
+static int mt7621_clk_probe(struct udevice *dev) +{
- struct mt7621_clk_priv *priv = dev_get_priv(dev);
- struct ofnode_phandle_args args;
- struct regmap *regmap;
- void __iomem *base;
- int ret;
- /* get corresponding sysc phandle */
- ret = dev_read_phandle_with_args(dev, "mediatek,sysc", NULL, 0, 0,
&args);
- if (ret)
return ret;
- regmap = syscon_node_to_regmap(args.node);
According to the Linux binding for this node, it is supposed to live under the syscon already. So you can do
syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
and skip the phandle.
- if (IS_ERR(regmap))
return PTR_ERR(regmap);
- base = regmap_get_range(regmap, 0);
- if (!base) {
dev_err(dev, "Unable to find sysc\n");
dev_dbg (see doc/develop/driver-model/design.rst)
return -ENODEV;
- }
- priv->sysc_base = ioremap_nocache((phys_addr_t)base, SYSC_MAP_SIZE);
- /* get corresponding memc phandle */
- ret = dev_read_phandle_with_args(dev, "mediatek,memc", NULL, 0, 0,
should be "ralink,memctl".
&args);
- if (ret)
return ret;
- regmap = syscon_node_to_regmap(args.node);
- if (IS_ERR(regmap))
return PTR_ERR(regmap);
These two steps can be compined with syscon_regmap_lookup_by_phandle.
- base = regmap_get_range(regmap, 0);
- if (!base) {
dev_err(dev, "Unable to find memc\n");
dev_dbg
return -ENODEV;
- }
- priv->memc_base = ioremap_nocache((phys_addr_t)base, MEMC_MAP_SIZE);
- mt7621_get_clocks(priv);
- 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/include/dt-bindings/clock/mt7621-clk.h b/include/dt-bindings/clock/mt7621-clk.h new file mode 100644 index 0000000000..b24aef351c --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (C) 2021 MediaTek Inc. All rights reserved.
- Author: Weijie Gao weijie.gao@mediatek.com
- */
+#ifndef _DT_BINDINGS_MT7621_CLK_H_ +#define _DT_BINDINGS_MT7621_CLK_H_
+/* Base clocks */ +#define CLK_MIPS_CNT 36 +#define CLK_SYS 35 +#define CLK_DDR 34 +#define CLK_CPU 33 +#define CLK_XTAL 32
Why is there a gap?
+/* Peripheral clocks */ +#define CLK_SDXC 30 +#define CLK_CRYPTO 29 +#define CLK_PCIE2 26 +#define CLK_PCIE1 25 +#define CLK_PCIE0 24 +#define CLK_GMAC 23 +#define CLK_UART3 21 +#define CLK_UART2 20 +#define CLK_UART1 19 +#define CLK_SPI 18 +#define CLK_I2S 17 +#define CLK_I2C 16 +#define CLK_NFI 15 +#define CLK_GDMA 14 +#define CLK_PIO 13 +#define CLK_PCM 11 +#define CLK_MC 10 +#define CLK_INTC 9 +#define CLK_TIMER 8 +#define CLK_SPDIFTX 7 +#define CLK_FE 6 +#define CLK_HSDMA 5
+#endif /* _DT_BINDINGS_MT7621_CLK_H_ */
This file looks very different from include/dt-bindings/clock/mt7621-clk.h in Linux. In particular, it is backwards, the IDs are different (HSDMA is 8 in Linux but 5 here), some of the IDs are named differently (SP_DIVTX vs SPDIFTX), and there is no MT7621 prefix. Can you comment on these? Are they deliberate? Note that in general, numerical IDs should be kept the same between Linux and U-Boot so we can use the same device tree. If you need to map between logical clock ID and a position in a register, I suggest something like
struct { u8 gate_bit; } clocks { [CLK_HSDMA] = { .gate_bit = 5 }, };
--Sean

On Fri, 2021-11-26 at 12:44 -0500, Sean Anderson wrote:
On 11/18/21 8:35 PM, Weijie Gao wrote:
This patch adds a clock driver for MediaTek MT7621 SoC. This driver provides clock gate control as well as getting clock frequency for CPU/SYS/XTAL and some peripherals.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
v2 changes: none
drivers/clk/mtmips/Makefile | 1 + drivers/clk/mtmips/clk-mt7621.c | 260 +++++++++++++++++++++++++ include/dt-bindings/clock/mt7621-clk.h | 42 ++++ 3 files changed, 303 insertions(+) create mode 100644 drivers/clk/mtmips/clk-mt7621.c create mode 100644 include/dt-bindings/clock/mt7621-clk.h
diff --git a/drivers/clk/mtmips/Makefile b/drivers/clk/mtmips/Makefile index 732e7f2545..ee8b5afe87 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 0000000000..3799d1806a --- /dev/null +++ b/drivers/clk/mtmips/clk-mt7621.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2021 MediaTek Inc. All Rights Reserved.
- Author: Weijie Gao weijie.gao@mediatek.com
- */
+#include <common.h> +#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/bitops.h> +#include <linux/io.h>
+#define SYSC_MAP_SIZE 0x100 +#define MEMC_MAP_SIZE 0x1000
+/* SYSC */ +#define SYSCFG0_REG 0x10 +#define XTAL_MODE_SEL_S 6 +#define XTAL_MODE_SEL_M 0x1c0
Please use genmask to define this:
#define XTAL_MODE_SEL_M GENMASK(8, 6)
and SEL_S is unnecessary, see commentary below.
+#define CLKCFG0_REG 0x2c +#define CPU_CLK_SEL_S 30 +#define CPU_CLK_SEL_M 0xc0000000 +#define PERI_CLK_SEL 0x10
+#define CLKCFG1_REG 0x30
+#define 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
+/* MEMC */ +#define MEMPLL1_REG 0x0604 +#define RG_MEPL_DIV2_SEL_S 1 +#define RG_MEPL_DIV2_SEL_M 0x06
+#define MEMPLL6_REG 0x0618 +#define MEMPLL18_REG 0x0648 +#define RG_MEPL_PREDIV_S 12 +#define RG_MEPL_PREDIV_M 0x3000 +#define RG_MEPL_FBDIV_S 4 +#define RG_MEPL_FBDIV_M 0x7f0
+/* Clock sources */ +#define CLK_SRC_CPU -1 +#define CLK_SRC_CPU_D2 -2 +#define CLK_SRC_DDR -3 +#define CLK_SRC_SYS -4 +#define CLK_SRC_XTAL -5 +#define CLK_SRC_PERI -6
Please use an enum. And why are these negative?
I'll rewrite this
+/* EPLL clock */ +#define EPLL_CLK 50000000
+struct mt7621_clk_priv {
- void __iomem *sysc_base;
- void __iomem *memc_base;
- int cpu_clk;
- int ddr_clk;
- int sys_clk;
- int xtal_clk;
+};
+static const int mt7621_clks[] = {
- [CLK_SYS] = CLK_SRC_SYS,
- [CLK_DDR] = CLK_SRC_DDR,
- [CLK_CPU] = CLK_SRC_CPU,
- [CLK_XTAL] = CLK_SRC_XTAL,
- [CLK_MIPS_CNT] = CLK_SRC_CPU_D2,
- [CLK_UART3] = CLK_SRC_PERI,
- [CLK_UART2] = CLK_SRC_PERI,
- [CLK_UART1] = CLK_SRC_PERI,
- [CLK_SPI] = CLK_SRC_SYS,
- [CLK_I2C] = CLK_SRC_PERI,
- [CLK_TIMER] = CLK_SRC_PERI,
+};
+static ulong mt7621_clk_get_rate(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- u32 val;
- if (clk->id >= ARRAY_SIZE(mt7621_clks))
return 0;
- switch (mt7621_clks[clk->id]) {
- case CLK_SRC_CPU:
return priv->cpu_clk;
- case CLK_SRC_CPU_D2:
return priv->cpu_clk / 2;
- 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 EPLL_CLK;
- default:
return 0;
-ENOSYS
- }
+}
+static int mt7621_clk_enable(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- if (clk->id > 31)
Please compare with a symbol.
OK. actually the clock gate register is 32-bit, and 31 is the MSB.
return -1;
-ENOSYS
- setbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk->id));
- return 0;
+}
+static int mt7621_clk_disable(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- if (clk->id > 31)
return -1;
- clrbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk->id));
- return 0;
+}
+const struct clk_ops mt7621_clk_ops = {
- .enable = mt7621_clk_enable,
- .disable = mt7621_clk_disable,
- .get_rate = mt7621_clk_get_rate,
+};
+static void mt7621_get_clocks(struct mt7621_clk_priv *priv) +{
- 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 = (bs & XTAL_MODE_SEL_M) >> XTAL_MODE_SEL_S;
xtal_sel = FIELD_GET(XTAL_MODE_SEL_M, bs);
got it.
- 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 ((clkcfg0 & CPU_CLK_SEL_M) >> CPU_CLK_SEL_S) {
ditto
- case 0:
cpu_clk = 500 * 1000 * 1000;
break;
- case 1:
mempll = readl(priv->memc_base + MEMPLL18_REG);
dividx = (mempll & RG_MEPL_PREDIV_M) >>
RG_MEPL_PREDIV_S;
fb = (mempll & RG_MEPL_FBDIV_M) >>
RG_MEPL_FBDIV_S;
ditto
xtal_div = 1 << xtal_div_tbl[dividx];
cpu_clk = (fb + 1) * xtal_clk / xtal_div;
break;
- default:
cpu_clk = xtal_clk;
- }
- ffiv = (cur_clk & CUR_CPU_FDIV_M) >> CUR_CPU_FDIV_S;
- ffrac = (cur_clk & CUR_CPU_FFRAC_M) >> CUR_CPU_FFRAC_S;
ditto
- cpu_clk = cpu_clk / ffiv * ffrac;
- mempll = readl(priv->memc_base + MEMPLL6_REG);
- dividx = (mempll & RG_MEPL_PREDIV_M) >> RG_MEPL_PREDIV_S;
- fb = (mempll & RG_MEPL_FBDIV_M) >> RG_MEPL_FBDIV_S;
ditto
- xtal_div = 1 << xtal_div_tbl[dividx];
- ddr_clk = fb * xtal_clk / xtal_div;
- bs = readl(priv->memc_base + MEMPLL1_REG);
- if (((bs & RG_MEPL_DIV2_SEL_M) >> RG_MEPL_DIV2_SEL_S) ==
ditto
and you can just use
if (!cond)
ddr_clk *= 2;
- priv->cpu_clk = cpu_clk;
- priv->sys_clk = cpu_clk / 4;
- priv->ddr_clk = ddr_clk;
- priv->xtal_clk = xtal_clk;
Please implement the above logic in get_rate(). For example:
static ulong do_mt7621_clk_get_rate() { ... switch (clk->id) { case CLK_SYS: cpu_clk = do_mt7621_clk_get_rate(priv, CLK_SYS); return IS_ERROR_VALUE(cpu_clk) ? cpu_clk : cpu_clk / 4; ... } }
static ulong mt7621_clk_get_rate() { struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
return do_mt7621_clk_get_rate(priv, clk->id); }
ok
+}
+static int mt7621_clk_probe(struct udevice *dev) +{
- struct mt7621_clk_priv *priv = dev_get_priv(dev);
- struct ofnode_phandle_args args;
- struct regmap *regmap;
- void __iomem *base;
- int ret;
- /* get corresponding sysc phandle */
- ret = dev_read_phandle_with_args(dev, "mediatek,sysc",
NULL, 0, 0,
&args);
- if (ret)
return ret;
- regmap = syscon_node_to_regmap(args.node);
According to the Linux binding for this node, it is supposed to live under the syscon already. So you can do
syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
and skip the phandle.
I'll try this
- if (IS_ERR(regmap))
return PTR_ERR(regmap);
- base = regmap_get_range(regmap, 0);
- if (!base) {
dev_err(dev, "Unable to find sysc\n");
dev_dbg (see doc/develop/driver-model/design.rst)
ok
return -ENODEV;
- }
- priv->sysc_base = ioremap_nocache((phys_addr_t)base,
SYSC_MAP_SIZE);
- /* get corresponding memc phandle */
- ret = dev_read_phandle_with_args(dev, "mediatek,memc",
NULL, 0, 0,
should be "ralink,memctl".
ok
&args);
- if (ret)
return ret;
- regmap = syscon_node_to_regmap(args.node);
- if (IS_ERR(regmap))
return PTR_ERR(regmap);
These two steps can be compined with syscon_regmap_lookup_by_phandle.
- base = regmap_get_range(regmap, 0);
- if (!base) {
dev_err(dev, "Unable to find memc\n");
dev_dbg
return -ENODEV;
- }
- priv->memc_base = ioremap_nocache((phys_addr_t)base,
MEMC_MAP_SIZE);
- mt7621_get_clocks(priv);
- 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/include/dt-bindings/clock/mt7621-clk.h b/include/dt- bindings/clock/mt7621-clk.h new file mode 100644 index 0000000000..b24aef351c --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (C) 2021 MediaTek Inc. All rights reserved.
- Author: Weijie Gao weijie.gao@mediatek.com
- */
+#ifndef _DT_BINDINGS_MT7621_CLK_H_ +#define _DT_BINDINGS_MT7621_CLK_H_
+/* Base clocks */ +#define CLK_MIPS_CNT 36 +#define CLK_SYS 35 +#define CLK_DDR 34 +#define CLK_CPU 33 +#define CLK_XTAL 32
Why is there a gap?
0~31 values are bits in clock gate register, and bit 31 is unused. values above 31 represent clock sources not defined in the gate register.
+/* Peripheral clocks */ +#define CLK_SDXC 30 +#define CLK_CRYPTO 29 +#define CLK_PCIE2 26 +#define CLK_PCIE1 25 +#define CLK_PCIE0 24 +#define CLK_GMAC 23 +#define CLK_UART3 21 +#define CLK_UART2 20 +#define CLK_UART1 19 +#define CLK_SPI 18 +#define CLK_I2S 17 +#define CLK_I2C 16 +#define CLK_NFI 15 +#define CLK_GDMA 14 +#define CLK_PIO 13 +#define CLK_PCM 11 +#define CLK_MC 10 +#define CLK_INTC 9 +#define CLK_TIMER 8 +#define CLK_SPDIFTX 7 +#define CLK_FE 6 +#define CLK_HSDMA 5
+#endif /* _DT_BINDINGS_MT7621_CLK_H_ */
This file looks very different from include/dt-bindings/clock/mt7621-clk.h in Linux. In particular, it is backwards, the IDs are different (HSDMA is 8 in Linux but 5 here),
5 directly represents the bit in clock gate register, which means a mapping must be done for the include/dt-bindings/clock/mt7621-clk.h (i.e. subtract by 3) in kernel.
btw, the file in kernel is not submitted by mediatek.
some of the IDs are named differently (SP_DIVTX vs SPDIFTX), and there is no MT7621 prefix. Can you comment on these? Are they deliberate?
The name SPDIFTX comes from the MT7621 programming guide of mediatek. Adding MT7621 seems better.
Note that in general, numerical IDs should be kept the same between Linux and U-Boot so we can use the same device tree. If you need to map between logical clock ID and a position in a register, I suggest something like
struct { u8 gate_bit; } clocks { [CLK_HSDMA] = { .gate_bit = 5 }, };
This is a driver dedicated for u-boot, and actually only the SYS clock is used. I believe using correct gate bit number is clearer.
--Sean

Hi Weijie,
(sorry for the delayed response)
On 12/3/21 5:06 AM, Weijie Gao wrote:
On Fri, 2021-11-26 at 12:44 -0500, Sean Anderson wrote:
On 11/18/21 8:35 PM, Weijie Gao wrote:
This patch adds a clock driver for MediaTek MT7621 SoC. This driver provides clock gate control as well as getting clock frequency for CPU/SYS/XTAL and some peripherals.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
v2 changes: none
drivers/clk/mtmips/Makefile | 1 + drivers/clk/mtmips/clk-mt7621.c | 260 +++++++++++++++++++++++++ include/dt-bindings/clock/mt7621-clk.h | 42 ++++ 3 files changed, 303 insertions(+) create mode 100644 drivers/clk/mtmips/clk-mt7621.c create mode 100644 include/dt-bindings/clock/mt7621-clk.h
diff --git a/drivers/clk/mtmips/Makefile b/drivers/clk/mtmips/Makefile index 732e7f2545..ee8b5afe87 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 0000000000..3799d1806a --- /dev/null +++ b/drivers/clk/mtmips/clk-mt7621.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2021 MediaTek Inc. All Rights Reserved.
- Author: Weijie Gao weijie.gao@mediatek.com
- */
+#include <common.h> +#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/bitops.h> +#include <linux/io.h>
+#define SYSC_MAP_SIZE 0x100 +#define MEMC_MAP_SIZE 0x1000
+/* SYSC */ +#define SYSCFG0_REG 0x10 +#define XTAL_MODE_SEL_S 6 +#define XTAL_MODE_SEL_M 0x1c0
Please use genmask to define this:
#define XTAL_MODE_SEL_M GENMASK(8, 6)
and SEL_S is unnecessary, see commentary below.
+#define CLKCFG0_REG 0x2c +#define CPU_CLK_SEL_S 30 +#define CPU_CLK_SEL_M 0xc0000000 +#define PERI_CLK_SEL 0x10
+#define CLKCFG1_REG 0x30
+#define 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
+/* MEMC */ +#define MEMPLL1_REG 0x0604 +#define RG_MEPL_DIV2_SEL_S 1 +#define RG_MEPL_DIV2_SEL_M 0x06
+#define MEMPLL6_REG 0x0618 +#define MEMPLL18_REG 0x0648 +#define RG_MEPL_PREDIV_S 12 +#define RG_MEPL_PREDIV_M 0x3000 +#define RG_MEPL_FBDIV_S 4 +#define RG_MEPL_FBDIV_M 0x7f0
+/* Clock sources */ +#define CLK_SRC_CPU -1 +#define CLK_SRC_CPU_D2 -2 +#define CLK_SRC_DDR -3 +#define CLK_SRC_SYS -4 +#define CLK_SRC_XTAL -5 +#define CLK_SRC_PERI -6
Please use an enum. And why are these negative?
I'll rewrite this
+/* EPLL clock */ +#define EPLL_CLK 50000000
+struct mt7621_clk_priv {
- void __iomem *sysc_base;
- void __iomem *memc_base;
- int cpu_clk;
- int ddr_clk;
- int sys_clk;
- int xtal_clk;
+};
+static const int mt7621_clks[] = {
- [CLK_SYS] = CLK_SRC_SYS,
- [CLK_DDR] = CLK_SRC_DDR,
- [CLK_CPU] = CLK_SRC_CPU,
- [CLK_XTAL] = CLK_SRC_XTAL,
- [CLK_MIPS_CNT] = CLK_SRC_CPU_D2,
- [CLK_UART3] = CLK_SRC_PERI,
- [CLK_UART2] = CLK_SRC_PERI,
- [CLK_UART1] = CLK_SRC_PERI,
- [CLK_SPI] = CLK_SRC_SYS,
- [CLK_I2C] = CLK_SRC_PERI,
- [CLK_TIMER] = CLK_SRC_PERI,
+};
+static ulong mt7621_clk_get_rate(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- u32 val;
- if (clk->id >= ARRAY_SIZE(mt7621_clks))
return 0;
- switch (mt7621_clks[clk->id]) {
- case CLK_SRC_CPU:
return priv->cpu_clk;
- case CLK_SRC_CPU_D2:
return priv->cpu_clk / 2;
- 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 EPLL_CLK;
- default:
return 0;
-ENOSYS
- }
+}
+static int mt7621_clk_enable(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- if (clk->id > 31)
Please compare with a symbol.
OK. actually the clock gate register is 32-bit, and 31 is the MSB.
see below
return -1;
-ENOSYS
- setbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk->id));
- return 0;
+}
+static int mt7621_clk_disable(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- if (clk->id > 31)
return -1;
- clrbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk->id));
- return 0;
+}
+const struct clk_ops mt7621_clk_ops = {
- .enable = mt7621_clk_enable,
- .disable = mt7621_clk_disable,
- .get_rate = mt7621_clk_get_rate,
+};
+static void mt7621_get_clocks(struct mt7621_clk_priv *priv) +{
- 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 = (bs & XTAL_MODE_SEL_M) >> XTAL_MODE_SEL_S;
xtal_sel = FIELD_GET(XTAL_MODE_SEL_M, bs);
got it.
- 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 ((clkcfg0 & CPU_CLK_SEL_M) >> CPU_CLK_SEL_S) {
ditto
- case 0:
cpu_clk = 500 * 1000 * 1000;
break;
- case 1:
mempll = readl(priv->memc_base + MEMPLL18_REG);
dividx = (mempll & RG_MEPL_PREDIV_M) >>
RG_MEPL_PREDIV_S;
fb = (mempll & RG_MEPL_FBDIV_M) >>
RG_MEPL_FBDIV_S;
ditto
xtal_div = 1 << xtal_div_tbl[dividx];
cpu_clk = (fb + 1) * xtal_clk / xtal_div;
break;
- default:
cpu_clk = xtal_clk;
- }
- ffiv = (cur_clk & CUR_CPU_FDIV_M) >> CUR_CPU_FDIV_S;
- ffrac = (cur_clk & CUR_CPU_FFRAC_M) >> CUR_CPU_FFRAC_S;
ditto
- cpu_clk = cpu_clk / ffiv * ffrac;
- mempll = readl(priv->memc_base + MEMPLL6_REG);
- dividx = (mempll & RG_MEPL_PREDIV_M) >> RG_MEPL_PREDIV_S;
- fb = (mempll & RG_MEPL_FBDIV_M) >> RG_MEPL_FBDIV_S;
ditto
- xtal_div = 1 << xtal_div_tbl[dividx];
- ddr_clk = fb * xtal_clk / xtal_div;
- bs = readl(priv->memc_base + MEMPLL1_REG);
- if (((bs & RG_MEPL_DIV2_SEL_M) >> RG_MEPL_DIV2_SEL_S) ==
ditto
and you can just use
if (!cond)
ddr_clk *= 2;
- priv->cpu_clk = cpu_clk;
- priv->sys_clk = cpu_clk / 4;
- priv->ddr_clk = ddr_clk;
- priv->xtal_clk = xtal_clk;
Please implement the above logic in get_rate(). For example:
static ulong do_mt7621_clk_get_rate() { ... switch (clk->id) { case CLK_SYS: cpu_clk = do_mt7621_clk_get_rate(priv, CLK_SYS); return IS_ERROR_VALUE(cpu_clk) ? cpu_clk : cpu_clk / 4; ... } }
static ulong mt7621_clk_get_rate() { struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
return do_mt7621_clk_get_rate(priv, clk->id); }
ok
+}
+static int mt7621_clk_probe(struct udevice *dev) +{
- struct mt7621_clk_priv *priv = dev_get_priv(dev);
- struct ofnode_phandle_args args;
- struct regmap *regmap;
- void __iomem *base;
- int ret;
- /* get corresponding sysc phandle */
- ret = dev_read_phandle_with_args(dev, "mediatek,sysc",
NULL, 0, 0,
&args);
- if (ret)
return ret;
- regmap = syscon_node_to_regmap(args.node);
According to the Linux binding for this node, it is supposed to live under the syscon already. So you can do
syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
and skip the phandle.
I'll try this
- if (IS_ERR(regmap))
return PTR_ERR(regmap);
- base = regmap_get_range(regmap, 0);
- if (!base) {
dev_err(dev, "Unable to find sysc\n");
dev_dbg (see doc/develop/driver-model/design.rst)
ok
return -ENODEV;
- }
- priv->sysc_base = ioremap_nocache((phys_addr_t)base,
SYSC_MAP_SIZE);
- /* get corresponding memc phandle */
- ret = dev_read_phandle_with_args(dev, "mediatek,memc",
NULL, 0, 0,
should be "ralink,memctl".
ok
&args);
- if (ret)
return ret;
- regmap = syscon_node_to_regmap(args.node);
- if (IS_ERR(regmap))
return PTR_ERR(regmap);
These two steps can be compined with syscon_regmap_lookup_by_phandle.
- base = regmap_get_range(regmap, 0);
- if (!base) {
dev_err(dev, "Unable to find memc\n");
dev_dbg
return -ENODEV;
- }
- priv->memc_base = ioremap_nocache((phys_addr_t)base,
MEMC_MAP_SIZE);
- mt7621_get_clocks(priv);
- 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/include/dt-bindings/clock/mt7621-clk.h b/include/dt- bindings/clock/mt7621-clk.h new file mode 100644 index 0000000000..b24aef351c --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (C) 2021 MediaTek Inc. All rights reserved.
- Author: Weijie Gao weijie.gao@mediatek.com
- */
+#ifndef _DT_BINDINGS_MT7621_CLK_H_ +#define _DT_BINDINGS_MT7621_CLK_H_
+/* Base clocks */ +#define CLK_MIPS_CNT 36 +#define CLK_SYS 35 +#define CLK_DDR 34 +#define CLK_CPU 33 +#define CLK_XTAL 32
Why is there a gap?
0~31 values are bits in clock gate register, and bit 31 is unused. values above 31 represent clock sources not defined in the gate register.
OK, but above your check is for clock IDs less than 31. So shouldn't it be something like
if (clk->id > CLK_SDXC) return -EINVAL;
+/* Peripheral clocks */ +#define CLK_SDXC 30 +#define CLK_CRYPTO 29 +#define CLK_PCIE2 26 +#define CLK_PCIE1 25 +#define CLK_PCIE0 24 +#define CLK_GMAC 23 +#define CLK_UART3 21 +#define CLK_UART2 20 +#define CLK_UART1 19 +#define CLK_SPI 18 +#define CLK_I2S 17 +#define CLK_I2C 16 +#define CLK_NFI 15 +#define CLK_GDMA 14 +#define CLK_PIO 13 +#define CLK_PCM 11 +#define CLK_MC 10 +#define CLK_INTC 9 +#define CLK_TIMER 8 +#define CLK_SPDIFTX 7 +#define CLK_FE 6 +#define CLK_HSDMA 5
+#endif /* _DT_BINDINGS_MT7621_CLK_H_ */
This file looks very different from include/dt-bindings/clock/mt7621-clk.h in Linux. In particular, it is backwards, the IDs are different (HSDMA is 8 in Linux but 5 here),
5 directly represents the bit in clock gate register, which means a mapping must be done for the include/dt-bindings/clock/mt7621-clk.h (i.e. subtract by 3) in kernel.
btw, the file in kernel is not submitted by mediatek.
I think aligning the defines with the names in the datasheet is a good idea. Can you send a patch to Linux to update the names of the defines?
some of the IDs are named differently (SP_DIVTX vs SPDIFTX), and there is no MT7621 prefix. Can you comment on these? Are they deliberate?
The name SPDIFTX comes from the MT7621 programming guide of mediatek. Adding MT7621 seems better.
Note that in general, numerical IDs should be kept the same between Linux and U-Boot so we can use the same device tree. If you need to map between logical clock ID and a position in a register, I suggest something like
struct { u8 gate_bit; } clocks { [CLK_HSDMA] = { .gate_bit = 5 }, };
This is a driver dedicated for u-boot, and actually only the SYS clock is used. I believe using correct gate bit number is clearer.
It is fine to implement only the necessary functionality, but it should be done in a way which is easy to extend in the future, and which won't cause us compatibility problems.
Generally, I would like to preserve both source and binary compatibility with Linux where possible. I am not sure whether they are hard requirements, so I made a post regarding that question [1]. For now, addressing my above comments will be fine.
--Sean
[1] https://lore.kernel.org/u-boot/c670a4cc-b234-03d4-adfb-e6a8560c2d86@gmail.co...

On Wed, 2021-12-15 at 11:11 -0500, Sean Anderson wrote:
Hi Weijie,
(sorry for the delayed response)
On 12/3/21 5:06 AM, Weijie Gao wrote:
On Fri, 2021-11-26 at 12:44 -0500, Sean Anderson wrote:
On 11/18/21 8:35 PM, Weijie Gao wrote:
This patch adds a clock driver for MediaTek MT7621 SoC. This driver provides clock gate control as well as getting clock frequency for CPU/SYS/XTAL and some peripherals.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
v2 changes: none
drivers/clk/mtmips/Makefile | 1 + drivers/clk/mtmips/clk-mt7621.c | 260 +++++++++++++++++++++++++ include/dt-bindings/clock/mt7621-clk.h | 42 ++++ 3 files changed, 303 insertions(+) create mode 100644 drivers/clk/mtmips/clk-mt7621.c create mode 100644 include/dt-bindings/clock/mt7621-clk.h
diff --git a/drivers/clk/mtmips/Makefile b/drivers/clk/mtmips/Makefile index 732e7f2545..ee8b5afe87 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 0000000000..3799d1806a --- /dev/null +++ b/drivers/clk/mtmips/clk-mt7621.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright (C) 2021 MediaTek Inc. All Rights Reserved.
- Author: Weijie Gao weijie.gao@mediatek.com
- */
+#include <common.h> +#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/bitops.h> +#include <linux/io.h>
+#define SYSC_MAP_SIZE 0x100 +#define MEMC_MAP_SIZE 0x1000
+/* SYSC */ +#define SYSCFG0_REG 0x10 +#define XTAL_MODE_SEL_S 6 +#define XTAL_MODE_SEL_M 0x1c0
Please use genmask to define this:
#define XTAL_MODE_SEL_M GENMASK(8, 6)
and SEL_S is unnecessary, see commentary below.
+#define CLKCFG0_REG 0x2c +#define CPU_CLK_SEL_S 30 +#define CPU_CLK_SEL_M 0xc0000000 +#define PERI_CLK_SEL 0x10
+#define CLKCFG1_REG 0x30
+#define 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
+/* MEMC */ +#define MEMPLL1_REG 0x0604 +#define RG_MEPL_DIV2_SEL_S 1 +#define RG_MEPL_DIV2_SEL_M 0x06
+#define MEMPLL6_REG 0x0618 +#define MEMPLL18_REG 0x0648 +#define RG_MEPL_PREDIV_S 12 +#define RG_MEPL_PREDIV_M 0x3000 +#define RG_MEPL_FBDIV_S 4 +#define RG_MEPL_FBDIV_M 0x7f0
+/* Clock sources */ +#define CLK_SRC_CPU -1 +#define CLK_SRC_CPU_D2 -2 +#define CLK_SRC_DDR -3 +#define CLK_SRC_SYS -4 +#define CLK_SRC_XTAL -5 +#define CLK_SRC_PERI -6
Please use an enum. And why are these negative?
I'll rewrite this
+/* EPLL clock */ +#define EPLL_CLK 50000000
+struct mt7621_clk_priv {
- void __iomem *sysc_base;
- void __iomem *memc_base;
- int cpu_clk;
- int ddr_clk;
- int sys_clk;
- int xtal_clk;
+};
+static const int mt7621_clks[] = {
- [CLK_SYS] = CLK_SRC_SYS,
- [CLK_DDR] = CLK_SRC_DDR,
- [CLK_CPU] = CLK_SRC_CPU,
- [CLK_XTAL] = CLK_SRC_XTAL,
- [CLK_MIPS_CNT] = CLK_SRC_CPU_D2,
- [CLK_UART3] = CLK_SRC_PERI,
- [CLK_UART2] = CLK_SRC_PERI,
- [CLK_UART1] = CLK_SRC_PERI,
- [CLK_SPI] = CLK_SRC_SYS,
- [CLK_I2C] = CLK_SRC_PERI,
- [CLK_TIMER] = CLK_SRC_PERI,
+};
+static ulong mt7621_clk_get_rate(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- u32 val;
- if (clk->id >= ARRAY_SIZE(mt7621_clks))
return 0;
- switch (mt7621_clks[clk->id]) {
- case CLK_SRC_CPU:
return priv->cpu_clk;
- case CLK_SRC_CPU_D2:
return priv->cpu_clk / 2;
- 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 EPLL_CLK;
- default:
return 0;
-ENOSYS
- }
+}
+static int mt7621_clk_enable(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- if (clk->id > 31)
Please compare with a symbol.
OK. actually the clock gate register is 32-bit, and 31 is the MSB.
see below
return -1;
-ENOSYS
- setbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk-
id));
- return 0;
+}
+static int mt7621_clk_disable(struct clk *clk) +{
- struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
- if (clk->id > 31)
return -1;
- clrbits_32(priv->sysc_base + CLKCFG1_REG, BIT(clk-
id));
- return 0;
+}
+const struct clk_ops mt7621_clk_ops = {
- .enable = mt7621_clk_enable,
- .disable = mt7621_clk_disable,
- .get_rate = mt7621_clk_get_rate,
+};
+static void mt7621_get_clocks(struct mt7621_clk_priv *priv) +{
- 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 = (bs & XTAL_MODE_SEL_M) >> XTAL_MODE_SEL_S;
xtal_sel = FIELD_GET(XTAL_MODE_SEL_M, bs);
got it.
- 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 ((clkcfg0 & CPU_CLK_SEL_M) >> CPU_CLK_SEL_S) {
ditto
- case 0:
cpu_clk = 500 * 1000 * 1000;
break;
- case 1:
mempll = readl(priv->memc_base +
MEMPLL18_REG);
dividx = (mempll & RG_MEPL_PREDIV_M) >>
RG_MEPL_PREDIV_S;
fb = (mempll & RG_MEPL_FBDIV_M) >>
RG_MEPL_FBDIV_S;
ditto
xtal_div = 1 << xtal_div_tbl[dividx];
cpu_clk = (fb + 1) * xtal_clk / xtal_div;
break;
- default:
cpu_clk = xtal_clk;
- }
- ffiv = (cur_clk & CUR_CPU_FDIV_M) >> CUR_CPU_FDIV_S;
- ffrac = (cur_clk & CUR_CPU_FFRAC_M) >>
CUR_CPU_FFRAC_S;
ditto
- cpu_clk = cpu_clk / ffiv * ffrac;
- mempll = readl(priv->memc_base + MEMPLL6_REG);
- dividx = (mempll & RG_MEPL_PREDIV_M) >>
RG_MEPL_PREDIV_S;
- fb = (mempll & RG_MEPL_FBDIV_M) >> RG_MEPL_FBDIV_S;
ditto
- xtal_div = 1 << xtal_div_tbl[dividx];
- ddr_clk = fb * xtal_clk / xtal_div;
- bs = readl(priv->memc_base + MEMPLL1_REG);
- if (((bs & RG_MEPL_DIV2_SEL_M) >> RG_MEPL_DIV2_SEL_S)
== 0)
ditto
and you can just use
if (!cond)
ddr_clk *= 2;
- priv->cpu_clk = cpu_clk;
- priv->sys_clk = cpu_clk / 4;
- priv->ddr_clk = ddr_clk;
- priv->xtal_clk = xtal_clk;
Please implement the above logic in get_rate(). For example:
static ulong do_mt7621_clk_get_rate() { ... switch (clk->id) { case CLK_SYS: cpu_clk = do_mt7621_clk_get_rate(priv, CLK_SYS); return IS_ERROR_VALUE(cpu_clk) ? cpu_clk : cpu_clk / 4; ... } }
static ulong mt7621_clk_get_rate() { struct mt7621_clk_priv *priv = dev_get_priv(clk->dev);
return do_mt7621_clk_get_rate(priv, clk->id); }
ok
+}
+static int mt7621_clk_probe(struct udevice *dev) +{
- struct mt7621_clk_priv *priv = dev_get_priv(dev);
- struct ofnode_phandle_args args;
- struct regmap *regmap;
- void __iomem *base;
- int ret;
- /* get corresponding sysc phandle */
- ret = dev_read_phandle_with_args(dev, "mediatek,sysc",
NULL, 0, 0,
&args);
- if (ret)
return ret;
- regmap = syscon_node_to_regmap(args.node);
According to the Linux binding for this node, it is supposed to live under the syscon already. So you can do
syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev)));
and skip the phandle.
I'll try this
- if (IS_ERR(regmap))
return PTR_ERR(regmap);
- base = regmap_get_range(regmap, 0);
- if (!base) {
dev_err(dev, "Unable to find sysc\n");
dev_dbg (see doc/develop/driver-model/design.rst)
ok
return -ENODEV;
- }
- priv->sysc_base = ioremap_nocache((phys_addr_t)base,
SYSC_MAP_SIZE);
- /* get corresponding memc phandle */
- ret = dev_read_phandle_with_args(dev, "mediatek,memc",
NULL, 0, 0,
should be "ralink,memctl".
ok
&args);
- if (ret)
return ret;
- regmap = syscon_node_to_regmap(args.node);
- if (IS_ERR(regmap))
return PTR_ERR(regmap);
These two steps can be compined with syscon_regmap_lookup_by_phandle.
- base = regmap_get_range(regmap, 0);
- if (!base) {
dev_err(dev, "Unable to find memc\n");
dev_dbg
return -ENODEV;
- }
- priv->memc_base = ioremap_nocache((phys_addr_t)base,
MEMC_MAP_SIZE);
- mt7621_get_clocks(priv);
- 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/include/dt-bindings/clock/mt7621-clk.h b/include/dt- bindings/clock/mt7621-clk.h new file mode 100644 index 0000000000..b24aef351c --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright (C) 2021 MediaTek Inc. All rights reserved.
- Author: Weijie Gao weijie.gao@mediatek.com
- */
+#ifndef _DT_BINDINGS_MT7621_CLK_H_ +#define _DT_BINDINGS_MT7621_CLK_H_
+/* Base clocks */ +#define CLK_MIPS_CNT 36 +#define CLK_SYS 35 +#define CLK_DDR 34 +#define CLK_CPU 33 +#define CLK_XTAL 32
Why is there a gap?
0~31 values are bits in clock gate register, and bit 31 is unused. values above 31 represent clock sources not defined in the gate register.
OK, but above your check is for clock IDs less than 31. So shouldn't it be something like
if (clk->id > CLK_SDXC) return -EINVAL;
+/* Peripheral clocks */ +#define CLK_SDXC 30 +#define CLK_CRYPTO 29 +#define CLK_PCIE2 26 +#define CLK_PCIE1 25 +#define CLK_PCIE0 24 +#define CLK_GMAC 23 +#define CLK_UART3 21 +#define CLK_UART2 20 +#define CLK_UART1 19 +#define CLK_SPI 18 +#define CLK_I2S 17 +#define CLK_I2C 16 +#define CLK_NFI 15 +#define CLK_GDMA 14 +#define CLK_PIO 13 +#define CLK_PCM 11 +#define CLK_MC 10 +#define CLK_INTC 9 +#define CLK_TIMER 8 +#define CLK_SPDIFTX 7 +#define CLK_FE 6 +#define CLK_HSDMA 5
+#endif /* _DT_BINDINGS_MT7621_CLK_H_ */
This file looks very different from include/dt-bindings/clock/mt7621-clk.h in Linux. In particular, it is backwards, the IDs are different (HSDMA is 8 in Linux but 5 here),
5 directly represents the bit in clock gate register, which means a mapping must be done for the include/dt-bindings/clock/mt7621-clk.h (i.e. subtract by 3) in kernel.
btw, the file in kernel is not submitted by mediatek.
I think aligning the defines with the names in the datasheet is a good idea. Can you send a patch to Linux to update the names of the defines?
some of the IDs are named differently (SP_DIVTX vs SPDIFTX), and there is no MT7621 prefix. Can you comment on these? Are they deliberate?
The name SPDIFTX comes from the MT7621 programming guide of mediatek. Adding MT7621 seems better.
Note that in general, numerical IDs should be kept the same between Linux and U-Boot so we can use the same device tree. If you need to map between logical clock ID and a position in a register, I suggest something like
struct { u8 gate_bit; } clocks { [CLK_HSDMA] = { .gate_bit = 5 }, };
This is a driver dedicated for u-boot, and actually only the SYS clock is used. I believe using correct gate bit number is clearer.
It is fine to implement only the necessary functionality, but it should be done in a way which is easy to extend in the future, and which won't cause us compatibility problems.
Generally, I would like to preserve both source and binary compatibility with Linux where possible. I am not sure whether they are hard requirements, so I made a post regarding that question [1]. For now, addressing my above comments will be fine.
I agreed. But now I decide to write a simple driver which provides only the bus clock. It seems that I don't have much time for rewrite the full clock driver at present.
--Sean
[1] https://lore.kernel.org/u-boot/c670a4cc-b234-03d4-adfb-e6a8560c2d 86@gmail.com/T/#u

On 12/27/21 3:06 AM, Weijie Gao wrote:
On Wed, 2021-12-15 at 11:11 -0500, Sean Anderson wrote:
It is fine to implement only the necessary functionality, but it should be done in a way which is easy to extend in the future, and which won't cause us compatibility problems.
Generally, I would like to preserve both source and binary compatibility with Linux where possible. I am not sure whether they are hard requirements, so I made a post regarding that question [1]. For now, addressing my above comments will be fine.
I agreed. But now I decide to write a simple driver which provides only the bus clock. It seems that I don't have much time for rewrite the full clock driver at present.
Well, all you have to do is something like
switch (clk->id) { case MT7621_CLK_TIMER: mask = CLKCFG1_TIMER; break; /* etc */ }
or use an array if you like that style better.
--Sean

This patch adds reset controller bits definition header file for MediaTek MT7621 SoC
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- include/dt-bindings/reset/mt7621-reset.h | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 include/dt-bindings/reset/mt7621-reset.h
diff --git a/include/dt-bindings/reset/mt7621-reset.h b/include/dt-bindings/reset/mt7621-reset.h new file mode 100644 index 0000000000..e129c531fc --- /dev/null +++ b/include/dt-bindings/reset/mt7621-reset.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2021 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_ */

This patch adds pinctrl support for MediaTek MT7621 SoC. The MT7621 SoC supports pinconf, but it is not the same as mt7628.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/pinctrl/mtmips/Kconfig | 9 + drivers/pinctrl/mtmips/Makefile | 1 + drivers/pinctrl/mtmips/pinctrl-mt7621.c | 307 ++++++++++++++++++ .../pinctrl/mtmips/pinctrl-mtmips-common.c | 4 +- .../pinctrl/mtmips/pinctrl-mtmips-common.h | 12 + 5 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 drivers/pinctrl/mtmips/pinctrl-mt7621.c
diff --git a/drivers/pinctrl/mtmips/Kconfig b/drivers/pinctrl/mtmips/Kconfig index 844d5b743f..456f3ea25d 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 ba945a89a7..8fece4f5fa 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 0000000000..c786d13d9e --- /dev/null +++ b/drivers/pinctrl/mtmips/pinctrl-mt7621.c @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 MediaTek Inc. All Rights Reserved. + * + * Author: Weijie Gao weijie.gao@mediatek.com + */ + +#include <common.h> +#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 e361916eb2..869b781068 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 b51d8f009c..1f1023ef42 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);

This patch adds NAND flash controller driver for MediaTek MT7621 SoC. The NAND flash controller of MT7621 supports only SLC NAND flashes. It supports 4~12 bits correction with maximum 4KB page size.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/mtd/nand/raw/Kconfig | 11 + drivers/mtd/nand/raw/Makefile | 1 + drivers/mtd/nand/raw/mt7621_nand.c | 1189 ++++++++++++++++++++++++++++ 3 files changed, 1201 insertions(+) create mode 100644 drivers/mtd/nand/raw/mt7621_nand.c
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index cb0c0a1581..fe87c521d7 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -475,6 +475,17 @@ config ROCKCHIP_NAND NFC v800: RK3308, RV1108 NFC v900: PX30, RK3326
+config NAND_MT7621 + bool "Support for MediaTek MT7621 NAND flash controller" + depends on SOC_MT7621 + select 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 diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index 6ec3581d20..6d6721a3be 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
diff --git a/drivers/mtd/nand/raw/mt7621_nand.c b/drivers/mtd/nand/raw/mt7621_nand.c new file mode 100644 index 0000000000..e4fe5320f1 --- /dev/null +++ b/drivers/mtd/nand/raw/mt7621_nand.c @@ -0,0 +1,1189 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021 MediaTek Incorporation. 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/mtd/mtd.h> +#include <linux/mtd/rawnand.h> + +/* NFI core registers */ +#define NFI_CNFG 0x000 +#define CNFG_OP_MODE_S 12 +#define CNFG_OP_MODE_M 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_S 12 +#define PAGEFMT_FDM_ECC_M GENMASK(15, 12) +#define PAGEFMT_FDM_S 8 +#define PAGEFMT_FDM_M GENMASK(11, 8) +#define PAGEFMT_SPARE_S 4 +#define PAGEFMT_SPARE_M GENMASK(5, 4) +#define PAGEFMT_PAGE_S 0 +#define PAGEFMT_PAGE_M GENMASK(1, 0) + +#define NFI_CON 0x008 +#define CON_NFI_SEC_S 12 +#define CON_NFI_SEC_M 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_S 28 +#define ACCCON_POECS_MAX 0x0f +#define ACCCON_POECS_DEF 3 +#define ACCCON_PRECS_S 22 +#define ACCCON_PRECS_MAX 0x3f +#define ACCCON_PRECS_DEF 3 +#define ACCCON_C2R_S 16 +#define ACCCON_C2R_MAX 0x3f +#define ACCCON_C2R_DEF 7 +#define ACCCON_W2R_S 12 +#define ACCCON_W2R_MAX 0x0f +#define ACCCON_W2R_DEF 7 +#define ACCCON_WH_S 8 +#define ACCCON_WH_MAX 0x0f +#define ACCCON_WH_DEF 15 +#define ACCCON_WST_S 4 +#define ACCCON_WST_MAX 0x0f +#define ACCCON_WST_DEF 15 +#define ACCCON_WST_MIN 3 +#define ACCCON_RLT_S 0 +#define ACCCON_RLT_MAX 0x0f +#define ACCCON_RLT_DEF 15 +#define ACCCON_RLT_MIN 3 + +#define NFI_CMD 0x020 + +#define NFI_ADDRNOB 0x030 +#define ADDR_ROW_NOB_S 4 +#define ADDR_ROW_NOB_M GENMASK(6, 4) +#define ADDR_COL_NOB_S 0 +#define ADDR_COL_NOB_M 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_S 4 +#define CB2R_TIME_M 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_S 16 +#define STA_NFI_FSM_M 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_S 12 +#define SEC_CNTR_M GENMASK(15, 12) +#define SEC_ADDR_S 0 +#define SEC_ADDR_M GENMASK(9, 0) + +#define NFI_CSEL 0x090 +#define CSEL_S 0 +#define CSEL_M 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_S 16 +#define ENC_CNFG_MSG_M GENMASK(28, 16) +#define ENC_MODE_S 4 +#define ENC_MODE_M GENMASK(5, 4) +#define ENC_MODE_NFI 1 +#define ENC_TNUM_S 0 +#define ENC_TNUM_M 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_S 16 +#define DEC_CS_M GENMASK(28, 16) +#define DEC_CON_S 12 +#define DEC_CON_M GENMASK(13, 12) +#define DEC_CON_EL 2 +#define DEC_MODE_S 4 +#define DEC_MODE_M GENMASK(5, 4) +#define DEC_MODE_NFI 1 +#define DEC_TNUM_S 0 +#define DEC_TNUM_M 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_EVEN_S 0 +#define DEC_EL_M 0x1fff +#define DEC_EL_BYTE_POS_S 3 +#define DEC_EL_BIT_POS_M GENMASK(3, 0) + +#define ECC_FDMADDR 0x13c + +/* ENCIDLE and DECIDLE */ +#define ECC_IDLE BIT(0) + +#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \ + ((tpoecs) << ACCCON_POECS_S | (tprecs) << ACCCON_PRECS_S | \ + (tc2r) << ACCCON_C2R_S | (tw2r) << ACCCON_W2R_S | \ + (twh) << ACCCON_WH_S | (twst) << ACCCON_WST_S | (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 + +struct mt7621_nfc { + struct nand_chip nand; + + void __iomem *nfi_regs; + void __iomem *ecc_regs; + + u32 spare_per_sector; +}; + +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, + ((val & SEC_CNTR_M) >> SEC_CNTR_S) >= 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_M | 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, CNFG_OP_CUSTOM << CNFG_OP_MODE_S); + 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; + + /* after each byte read, the NFI_STA reg is reset by the hardware */ + reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S; + if (reg != 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_M | 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; + + reg = (nfi_read32(nfc, NFI_STA) & STA_NFI_FSM_M) >> STA_NFI_FSM_S; + if (reg != 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_M | 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 spare_per_sector, 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; + + spare_per_sector = mtd->oobsize / nand->ecc.steps; + + ecc_cap = mt7621_nfc_calc_ecc_strength(nfc, + spare_per_sector - NFI_FDM_SIZE); + if (ecc_cap < 0) + return ecc_cap; + + /* Sector + FDM */ + encode_block_size = (nand->ecc.size + NFI_FDM_SIZE) * 8; + ecc_enccfg = ecc_cap | (ENC_MODE_NFI << ENC_MODE_S) | + (encode_block_size << ENC_CNFG_MSG_S); + + /* 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 | (DEC_MODE_NFI << DEC_MODE_S) | + (decode_block_size << DEC_CS_S) | + (DEC_CON_EL << DEC_CON_S) | 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 = i | (spare_size << PAGEFMT_SPARE_S) | + (NFI_FDM_SIZE << PAGEFMT_FDM_S) | + (NFI_FDM_SIZE << PAGEFMT_FDM_ECC_S); + + 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 - 4) * 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, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) | + CNFG_READ_MODE | CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); + + mt7621_ecc_decoder_op(nfc, true); + + nfi_write16(nfc, NFI_CON, + CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S)); + + 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, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) | + CNFG_READ_MODE); + + nfi_write16(nfc, NFI_CON, + CON_NFI_BRD | (nand->ecc.steps << CON_NFI_SEC_S)); + + 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, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S) | + CNFG_AUTO_FMT_EN | CNFG_HW_ECC_EN); + + mt7621_ecc_encoder_op(nfc, true); + + mt7621_nfc_write_fdm(nfc); + + nfi_write16(nfc, NFI_CON, + CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S)); + + 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, (CNFG_OP_CUSTOM << CNFG_OP_MODE_S)); + + nfi_write16(nfc, NFI_CON, + CON_NFI_BWR | (nand->ecc.steps << CON_NFI_SEC_S)); + + 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, (void *)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); +} + +void board_nand_init(void) +{ + nfc_dev.nfi_regs = (void __iomem *)CKSEG1ADDR(NFI_BASE); + nfc_dev.ecc_regs = (void __iomem *)CKSEG1ADDR(NFI_ECC_BASE); + + mt7621_nfc_init_chip(&nfc_dev); +}

This patch makes xhci-mtk driver available for MediaTek MT7621 SoC
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/usb/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index ccecb5a3b0..f2c060e692 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -34,7 +34,7 @@ config USB_XHCI_DWC3_OF_SIMPLE
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.

This patch makes mtk-tphy driver available for MediaTek MT7621 SoC
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/phy/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 4767d215f3..6ab99d2643 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

This patch makes mt7621_spi driver available for MediaTek MT7621 SoC
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index d07e9a28af..a43e652231 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -219,7 +219,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

This patch makes mt7621_gpio driver available for MediaTek MT7621 SoC
Reviewed-by: Stefan Roese sr@denx.de Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 40abc33772..8c49ca3f50 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -501,7 +501,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.

This patch makes mt7621_wdt driver available for MediaTek MT7621 SoC
Reviewed-by: Stefan Roese sr@denx.de Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index d306054a8c..cf383de973 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -173,7 +173,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.

This patch adds SDXC support for MediaTek MT7621 SoC
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/mmc/mtk-sd.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c index 8599f095bc..1199052a89 100644 --- a/drivers/mmc/mtk-sd.c +++ b/drivers/mmc/mtk-sd.c @@ -1746,6 +1746,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, @@ -1794,6 +1806,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 },

On 11/19/21 10:37 AM, Weijie Gao wrote:
This patch adds SDXC support for MediaTek MT7621 SoC
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
v2 changes: none
drivers/mmc/mtk-sd.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c index 8599f095bc..1199052a89 100644 --- a/drivers/mmc/mtk-sd.c +++ b/drivers/mmc/mtk-sd.c @@ -1746,6 +1746,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, @@ -1794,6 +1806,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 },

This patch adds GMAC support for MediaTek MT7621 SoC. MT7621 has the same GMAC/Switch configuration as MT7623.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- drivers/net/mtk_eth.c | 27 +++++++++++++++++++++------ drivers/net/mtk_eth.h | 8 ++++++++ 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c index 26f02847a2..3b42c99c2a 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 { @@ -669,12 +670,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 +739,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); @@ -1437,6 +1445,12 @@ static int mtk_eth_of_to_plat(struct udevice *dev) return -ENODEV; }
+ if (priv->soc == SOC_MT7621) { + /* ioremap is needed for MIPS platform */ + priv->ethsys_base = + ioremap_nocache((phys_addr_t)priv->ethsys_base, 0x100); + } + /* Reset controllers */ ret = reset_get_by_name(dev, "fe", &priv->rst_fe); if (ret) { @@ -1542,6 +1556,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/net/mtk_eth.h b/drivers/net/mtk_eth.h index 057ecfaabf..4a8c66c671 100644 --- a/drivers/net/mtk_eth.h +++ b/drivers/net/mtk_eth.h @@ -412,4 +412,12 @@ #define PHY_POWER_SAVING_M 0x300 #define PHY_POWER_SAVING_TX 0x0
+#ifndef CONFIG_SYS_NONCACHED_MEMORY +/* + * noncached_alloc is provided only for ARM. Add a prototype here for other + * platforms to suppress compilation warning. + */ +phys_addr_t noncached_alloc(size_t size, size_t align); +#endif + #endif /* _MTK_ETH_H_ */

On Fri, Nov 19, 2021 at 3:37 AM Weijie Gao weijie.gao@mediatek.com wrote:
This patch adds GMAC support for MediaTek MT7621 SoC. MT7621 has the same GMAC/Switch configuration as MT7623.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
v2 changes: none
drivers/net/mtk_eth.c | 27 +++++++++++++++++++++------ drivers/net/mtk_eth.h | 8 ++++++++ 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c index 26f02847a2..3b42c99c2a 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 { @@ -669,12 +670,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 +739,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);
@@ -1437,6 +1445,12 @@ static int mtk_eth_of_to_plat(struct udevice *dev) return -ENODEV; }
if (priv->soc == SOC_MT7621) {
/* ioremap is needed for MIPS platform */
For MIPS ? you need to io map for every platform, some platform just works without it.
priv->ethsys_base =
ioremap_nocache((phys_addr_t)priv->ethsys_base, 0x100);
}
/* Reset controllers */ ret = reset_get_by_name(dev, "fe", &priv->rst_fe); if (ret) {
@@ -1542,6 +1556,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/net/mtk_eth.h b/drivers/net/mtk_eth.h index 057ecfaabf..4a8c66c671 100644 --- a/drivers/net/mtk_eth.h +++ b/drivers/net/mtk_eth.h @@ -412,4 +412,12 @@ #define PHY_POWER_SAVING_M 0x300 #define PHY_POWER_SAVING_TX 0x0
+#ifndef CONFIG_SYS_NONCACHED_MEMORY +/*
- noncached_alloc is provided only for ARM. Add a prototype here for other
- platforms to suppress compilation warning.
- */
+phys_addr_t noncached_alloc(size_t size, size_t align);
That's not the place for that. I assume that it fails on MIPS, please create a patch for MIPS arch.
+#endif
#endif /* _MTK_ETH_H_ */
2.17.1

On Sun, 2021-11-21 at 21:14 +0200, Ramon Fried wrote:
On Fri, Nov 19, 2021 at 3:37 AM Weijie Gao weijie.gao@mediatek.com wrote:
This patch adds GMAC support for MediaTek MT7621 SoC. MT7621 has the same GMAC/Switch configuration as MT7623.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
v2 changes: none
drivers/net/mtk_eth.c | 27 +++++++++++++++++++++------ drivers/net/mtk_eth.h | 8 ++++++++ 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c index 26f02847a2..3b42c99c2a 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 { @@ -669,12 +670,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 +739,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); @@ -1437,6 +1445,12 @@ static int mtk_eth_of_to_plat(struct udevice *dev) return -ENODEV; }
if (priv->soc == SOC_MT7621) {
/* ioremap is needed for MIPS platform */
For MIPS ? you need to io map for every platform, some platform just works without it.
That's my mistake. The map_sysmem called by regmap_get_range is a dummy function for both arm and mips. But for arm the virtual address in u-boot is identical to the physical address and I didn't notice that.
I'll make ioremap unconditional.
priv->ethsys_base =
ioremap_nocache((phys_addr_t)priv-
ethsys_base, 0x100);
}
/* Reset controllers */ ret = reset_get_by_name(dev, "fe", &priv->rst_fe); if (ret) {
@@ -1542,6 +1556,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/net/mtk_eth.h b/drivers/net/mtk_eth.h index 057ecfaabf..4a8c66c671 100644 --- a/drivers/net/mtk_eth.h +++ b/drivers/net/mtk_eth.h @@ -412,4 +412,12 @@ #define PHY_POWER_SAVING_M 0x300 #define PHY_POWER_SAVING_TX 0x0
+#ifndef CONFIG_SYS_NONCACHED_MEMORY +/*
- noncached_alloc is provided only for ARM. Add a prototype here
for other
- platforms to suppress compilation warning.
- */
+phys_addr_t noncached_alloc(size_t size, size_t align);
That's not the place for that. I assume that it fails on MIPS, please create a patch for MIPS arch.
OK. I'll create patches for MIPS
+#endif
#endif /* _MTK_ETH_H_ */
2.17.1

Update maintainer for MediaTek MIPS platform
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- v2 changes: none --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS index 5069f18806..7d65856743 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -855,15 +855,20 @@ 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: 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/net/mt7620-eth.c F: drivers/phy/mt7620-usb-phy.c F: drivers/reset/reset-mtmips.c
participants (4)
-
Jaehoon Chung
-
Ramon Fried
-
Sean Anderson
-
Weijie Gao