All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/14] Add support for MediaTek MT7621 SoC
@ 2021-11-19  1:35 Weijie Gao
  2021-11-19  1:35 ` [PATCH v2 01/14] mips: mtmips: add " Weijie Gao
                   ` (13 more replies)
  0 siblings, 14 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:35 UTC (permalink / raw)
  To: u-boot; +Cc: GSS_MTK_Uboot_upstream, Weijie Gao

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

-- 
2.17.1


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 01/14] mips: mtmips: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
@ 2021-11-19  1:35 ` Weijie Gao
  2021-11-19  1:35 ` [PATCH v2 02/14] mips: mtmips: add two reference boards for mt7621 Weijie Gao
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:35 UTC (permalink / raw)
  To: u-boot; +Cc: GSS_MTK_Uboot_upstream, Daniel Schwierzeck, Weijie Gao

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 = <&eth_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 */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 02/14] mips: mtmips: add two reference boards for mt7621
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
  2021-11-19  1:35 ` [PATCH v2 01/14] mips: mtmips: add " Weijie Gao
@ 2021-11-19  1:35 ` Weijie Gao
  2021-11-19  1:35 ` [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC Weijie Gao
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:35 UTC (permalink / raw)
  To: u-boot
  Cc: GSS_MTK_Uboot_upstream, Daniel Schwierzeck, Stefan Roese, Weijie Gao

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";
+};
+
+&eth {
+	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>;
+	};
+};
+
+&eth {
+	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 */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
  2021-11-19  1:35 ` [PATCH v2 01/14] mips: mtmips: add " Weijie Gao
  2021-11-19  1:35 ` [PATCH v2 02/14] mips: mtmips: add two reference boards for mt7621 Weijie Gao
@ 2021-11-19  1:35 ` Weijie Gao
  2021-11-26 17:44   ` Sean Anderson
  2021-11-19  1:36 ` [PATCH v2 04/14] reset: mtmips: add reset controller support " Weijie Gao
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:35 UTC (permalink / raw)
  To: u-boot; +Cc: GSS_MTK_Uboot_upstream, Lukasz Majewski, Weijie Gao

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_ */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 04/14] reset: mtmips: add reset controller support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (2 preceding siblings ...)
  2021-11-19  1:35 ` [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC Weijie Gao
@ 2021-11-19  1:36 ` Weijie Gao
  2021-11-19  1:36 ` [PATCH v2 05/14] pinctrl: mtmips: add " Weijie Gao
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:36 UTC (permalink / raw)
  To: u-boot; +Cc: GSS_MTK_Uboot_upstream, Weijie Gao

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_ */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 05/14] pinctrl: mtmips: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (3 preceding siblings ...)
  2021-11-19  1:36 ` [PATCH v2 04/14] reset: mtmips: add reset controller support " Weijie Gao
@ 2021-11-19  1:36 ` Weijie Gao
  2021-11-19  1:36 ` [PATCH v2 06/14] nand: raw: " Weijie Gao
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:36 UTC (permalink / raw)
  To: u-boot; +Cc: GSS_MTK_Uboot_upstream, Weijie Gao

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);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 06/14] nand: raw: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (4 preceding siblings ...)
  2021-11-19  1:36 ` [PATCH v2 05/14] pinctrl: mtmips: add " Weijie Gao
@ 2021-11-19  1:36 ` Weijie Gao
  2021-11-19  1:36 ` [PATCH v2 07/14] usb: xhci-mtk: " Weijie Gao
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:36 UTC (permalink / raw)
  To: u-boot
  Cc: GSS_MTK_Uboot_upstream, Michal Simek, Kever Yang, Yifeng Zhao,
	Alex Nemirovsky, Haolin Li, Kate Liu, Zhengxun Li, Weijie Gao

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);
+}
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 07/14] usb: xhci-mtk: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (5 preceding siblings ...)
  2021-11-19  1:36 ` [PATCH v2 06/14] nand: raw: " Weijie Gao
@ 2021-11-19  1:36 ` Weijie Gao
  2021-11-19  1:36 ` [PATCH v2 08/14] phy: mtk-tphy: " Weijie Gao
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:36 UTC (permalink / raw)
  To: u-boot
  Cc: GSS_MTK_Uboot_upstream, Marek Vasut, Marek Behún,
	Michal Simek, Giulio Benetti, Weijie Gao

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.
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 08/14] phy: mtk-tphy: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (6 preceding siblings ...)
  2021-11-19  1:36 ` [PATCH v2 07/14] usb: xhci-mtk: " Weijie Gao
@ 2021-11-19  1:36 ` Weijie Gao
  2021-11-19  1:36 ` [PATCH v2 09/14] spi: " Weijie Gao
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:36 UTC (permalink / raw)
  To: u-boot
  Cc: GSS_MTK_Uboot_upstream, Neil Armstrong, Kishon Vijay Abraham I,
	Lokesh Vutla, Jean-Jacques Hiblot, Vignesh Raghavendra,
	Stephan Gerhold, Alan Douglas, Ye Li, Weijie Gao

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
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 09/14] spi: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (7 preceding siblings ...)
  2021-11-19  1:36 ` [PATCH v2 08/14] phy: mtk-tphy: " Weijie Gao
@ 2021-11-19  1:36 ` Weijie Gao
  2021-11-19  1:36 ` [PATCH v2 10/14] gpio: " Weijie Gao
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:36 UTC (permalink / raw)
  To: u-boot; +Cc: GSS_MTK_Uboot_upstream, Jagan Teki, Weijie Gao

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
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 10/14] gpio: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (8 preceding siblings ...)
  2021-11-19  1:36 ` [PATCH v2 09/14] spi: " Weijie Gao
@ 2021-11-19  1:36 ` Weijie Gao
  2021-11-19  1:36 ` [PATCH v2 11/14] watchdog: " Weijie Gao
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:36 UTC (permalink / raw)
  To: u-boot
  Cc: GSS_MTK_Uboot_upstream, Simon Glass, Stefan Roese, Michal Simek,
	Linus Walleij, Harm Berntsen, Hannes Schmelzer,
	Sebastian Reichel, Stephan Gerhold, Weijie Gao

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.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 11/14] watchdog: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (9 preceding siblings ...)
  2021-11-19  1:36 ` [PATCH v2 10/14] gpio: " Weijie Gao
@ 2021-11-19  1:36 ` Weijie Gao
  2021-11-19  1:37 ` [PATCH v2 12/14] mmc: mediatek: " Weijie Gao
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:36 UTC (permalink / raw)
  To: u-boot
  Cc: GSS_MTK_Uboot_upstream, Stefan Roese, Jagan Teki, Chris Packham,
	Chia-Wei, Wang, Samuel Holland, Pali Rohár, Jan Kiszka,
	Rasmus Villemoes, Weijie Gao

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.
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 12/14] mmc: mediatek: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (10 preceding siblings ...)
  2021-11-19  1:36 ` [PATCH v2 11/14] watchdog: " Weijie Gao
@ 2021-11-19  1:37 ` Weijie Gao
  2021-11-22 23:41   ` Jaehoon Chung
  2021-11-19  1:37 ` [PATCH v2 13/14] net: " Weijie Gao
  2021-11-19  1:37 ` [PATCH v2 14/14] MAINTAINERS: update maintainer for MediaTek MIPS platform Weijie Gao
  13 siblings, 1 reply; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:37 UTC (permalink / raw)
  To: u-boot; +Cc: GSS_MTK_Uboot_upstream, Peng Fan, Jaehoon Chung, Weijie Gao

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 },
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 13/14] net: mediatek: add support for MediaTek MT7621 SoC
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (11 preceding siblings ...)
  2021-11-19  1:37 ` [PATCH v2 12/14] mmc: mediatek: " Weijie Gao
@ 2021-11-19  1:37 ` Weijie Gao
  2021-11-21 19:14   ` Ramon Fried
  2021-11-19  1:37 ` [PATCH v2 14/14] MAINTAINERS: update maintainer for MediaTek MIPS platform Weijie Gao
  13 siblings, 1 reply; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:37 UTC (permalink / raw)
  To: u-boot; +Cc: GSS_MTK_Uboot_upstream, Joe Hershberger, Ramon Fried, Weijie Gao

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_ */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 14/14] MAINTAINERS: update maintainer for MediaTek MIPS platform
  2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
                   ` (12 preceding siblings ...)
  2021-11-19  1:37 ` [PATCH v2 13/14] net: " Weijie Gao
@ 2021-11-19  1:37 ` Weijie Gao
  13 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-19  1:37 UTC (permalink / raw)
  To: u-boot; +Cc: GSS_MTK_Uboot_upstream, Weijie Gao

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
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 13/14] net: mediatek: add support for MediaTek MT7621 SoC
  2021-11-19  1:37 ` [PATCH v2 13/14] net: " Weijie Gao
@ 2021-11-21 19:14   ` Ramon Fried
  2021-11-22  8:09     ` Weijie Gao
  0 siblings, 1 reply; 23+ messages in thread
From: Ramon Fried @ 2021-11-21 19:14 UTC (permalink / raw)
  To: Weijie Gao; +Cc: U-Boot Mailing List, GSS_MTK_Uboot_upstream, Joe Hershberger

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
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 13/14] net: mediatek: add support for MediaTek MT7621 SoC
  2021-11-21 19:14   ` Ramon Fried
@ 2021-11-22  8:09     ` Weijie Gao
  0 siblings, 0 replies; 23+ messages in thread
From: Weijie Gao @ 2021-11-22  8:09 UTC (permalink / raw)
  To: Ramon Fried; +Cc: U-Boot Mailing List, GSS_MTK_Uboot_upstream, Joe Hershberger

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
> > 

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 12/14] mmc: mediatek: add support for MediaTek MT7621 SoC
  2021-11-19  1:37 ` [PATCH v2 12/14] mmc: mediatek: " Weijie Gao
@ 2021-11-22 23:41   ` Jaehoon Chung
  0 siblings, 0 replies; 23+ messages in thread
From: Jaehoon Chung @ 2021-11-22 23:41 UTC (permalink / raw)
  To: Weijie Gao, u-boot; +Cc: GSS_MTK_Uboot_upstream, Peng Fan

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 },
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC
  2021-11-19  1:35 ` [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC Weijie Gao
@ 2021-11-26 17:44   ` Sean Anderson
  2021-12-03 10:06     ` Weijie Gao
  0 siblings, 1 reply; 23+ messages in thread
From: Sean Anderson @ 2021-11-26 17:44 UTC (permalink / raw)
  To: Weijie Gao, u-boot; +Cc: GSS_MTK_Uboot_upstream, Lukasz Majewski

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

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC
  2021-11-26 17:44   ` Sean Anderson
@ 2021-12-03 10:06     ` Weijie Gao
  2021-12-15 16:11       ` Sean Anderson
  0 siblings, 1 reply; 23+ messages in thread
From: Weijie Gao @ 2021-12-03 10:06 UTC (permalink / raw)
  To: Sean Anderson, u-boot; +Cc: GSS_MTK_Uboot_upstream, Lukasz Majewski

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) ==
> > 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.

> 
> > +/* 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

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC
  2021-12-03 10:06     ` Weijie Gao
@ 2021-12-15 16:11       ` Sean Anderson
  2021-12-27  8:06         ` Weijie Gao
  0 siblings, 1 reply; 23+ messages in thread
From: Sean Anderson @ 2021-12-15 16:11 UTC (permalink / raw)
  To: Weijie Gao, u-boot; +Cc: GSS_MTK_Uboot_upstream, Lukasz Majewski

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.

--Sean

[1] https://lore.kernel.org/u-boot/c670a4cc-b234-03d4-adfb-e6a8560c2d86@gmail.com/T/#u

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC
  2021-12-15 16:11       ` Sean Anderson
@ 2021-12-27  8:06         ` Weijie Gao
  2021-12-31  2:30           ` Sean Anderson
  0 siblings, 1 reply; 23+ messages in thread
From: Weijie Gao @ 2021-12-27  8:06 UTC (permalink / raw)
  To: Sean Anderson, u-boot; +Cc: GSS_MTK_Uboot_upstream, Lukasz Majewski

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

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC
  2021-12-27  8:06         ` Weijie Gao
@ 2021-12-31  2:30           ` Sean Anderson
  0 siblings, 0 replies; 23+ messages in thread
From: Sean Anderson @ 2021-12-31  2:30 UTC (permalink / raw)
  To: Weijie Gao, u-boot; +Cc: GSS_MTK_Uboot_upstream, Lukasz Majewski

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

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2021-12-31  2:30 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-19  1:35 [PATCH v2 00/14] Add support for MediaTek MT7621 SoC Weijie Gao
2021-11-19  1:35 ` [PATCH v2 01/14] mips: mtmips: add " Weijie Gao
2021-11-19  1:35 ` [PATCH v2 02/14] mips: mtmips: add two reference boards for mt7621 Weijie Gao
2021-11-19  1:35 ` [PATCH v2 03/14] clk: mtmips: add clock driver for MediaTek MT7621 SoC Weijie Gao
2021-11-26 17:44   ` Sean Anderson
2021-12-03 10:06     ` Weijie Gao
2021-12-15 16:11       ` Sean Anderson
2021-12-27  8:06         ` Weijie Gao
2021-12-31  2:30           ` Sean Anderson
2021-11-19  1:36 ` [PATCH v2 04/14] reset: mtmips: add reset controller support " Weijie Gao
2021-11-19  1:36 ` [PATCH v2 05/14] pinctrl: mtmips: add " Weijie Gao
2021-11-19  1:36 ` [PATCH v2 06/14] nand: raw: " Weijie Gao
2021-11-19  1:36 ` [PATCH v2 07/14] usb: xhci-mtk: " Weijie Gao
2021-11-19  1:36 ` [PATCH v2 08/14] phy: mtk-tphy: " Weijie Gao
2021-11-19  1:36 ` [PATCH v2 09/14] spi: " Weijie Gao
2021-11-19  1:36 ` [PATCH v2 10/14] gpio: " Weijie Gao
2021-11-19  1:36 ` [PATCH v2 11/14] watchdog: " Weijie Gao
2021-11-19  1:37 ` [PATCH v2 12/14] mmc: mediatek: " Weijie Gao
2021-11-22 23:41   ` Jaehoon Chung
2021-11-19  1:37 ` [PATCH v2 13/14] net: " Weijie Gao
2021-11-21 19:14   ` Ramon Fried
2021-11-22  8:09     ` Weijie Gao
2021-11-19  1:37 ` [PATCH v2 14/14] MAINTAINERS: update maintainer for MediaTek MIPS platform Weijie Gao

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.