[U-Boot] [PATCH 00/11] Add ethernet driver for MediaTek SoCs

This patch series mainly add ethernet support for MeidaTek MT7623/MT7629:
The ethernet related patches: - Add reset controller: currently binds with the ethsys to provide reset capabilities for ethernet components. - Ethernet driver: supports one GMAC only. Uses MT7530 gigabit switch for MT7623 and built-in gigabit PHY for MT7629.
Other patch: - SMP support for MT7629: allow kernel to make use of two cores.
Mark Lee (5): ethernet: MediaTek: add ethernet driver for MediaTek ARM-based SoCs arm: dts: add ethernet related node for MT7623 SoC arm: dts: add ethernet related node for MT7629 SoC arm: MediaTek: add ethernet support for MT7623 boards arm: MediaTek: add ethernet support for MT7629 boards
Weijie Gao (6): mt7623: fix a typo in include/configs/mt7623.h mt7629: use linux kernel compatible SMP initialization reset: MedaiTek: add reset controller driver for MediaTek SoCs clk: MediaTek: bind ethsys reset controller MAINTAINERS: ARM MEDIATEK: update file entries configs: MediaTek: use OF_SEPARATE instead of OF_EMBED
MAINTAINERS | 2 + arch/arm/dts/mt7623.dtsi | 21 +- arch/arm/dts/mt7623n-bananapi-bpi-r2.dts | 13 + arch/arm/dts/mt7629-rfb.dts | 11 + arch/arm/dts/mt7629.dtsi | 43 + arch/arm/include/asm/arch-mediatek/reset.h | 13 + arch/arm/mach-mediatek/mt7629/lowlevel_init.S | 52 +- configs/mt7623n_bpir2_defconfig | 8 +- configs/mt7629_rfb_defconfig | 7 +- drivers/clk/mediatek/clk-mt7623.c | 15 + drivers/clk/mediatek/clk-mt7629.c | 15 + drivers/clk/mediatek/clk-mtk.h | 2 + drivers/net/Kconfig | 10 + drivers/net/Makefile | 1 + drivers/net/mtk_eth.c | 1175 +++++++++++++++++ drivers/net/mtk_eth.h | 286 ++++ drivers/reset/Kconfig | 7 + drivers/reset/Makefile | 1 + drivers/reset/reset-mediatek.c | 102 ++ include/configs/mt7623.h | 7 +- include/configs/mt7629.h | 5 + include/dt-bindings/reset/mtk-reset.h | 18 + 22 files changed, 1802 insertions(+), 12 deletions(-) create mode 100644 arch/arm/include/asm/arch-mediatek/reset.h create mode 100644 drivers/net/mtk_eth.c create mode 100644 drivers/net/mtk_eth.h create mode 100644 drivers/reset/reset-mediatek.c create mode 100644 include/dt-bindings/reset/mtk-reset.h

Fix typo: neede -> needed
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- include/configs/mt7623.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/configs/mt7623.h b/include/configs/mt7623.h index 68da920e300..ba763501cf2 100644 --- a/include/configs/mt7623.h +++ b/include/configs/mt7623.h @@ -46,7 +46,7 @@ /* DRAM */ #define CONFIG_SYS_SDRAM_BASE 0x80000000
-/* This is neede for kernel booting */ +/* This is needed for kernel booting */ #define FDT_HIGH "fdt_high=0xac000000\0"
/* Extra environment variables */

On Thu, Dec 20, 2018 at 04:12:49PM +0800, Weijie Gao wrote:
Fix typo: neede -> needed
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
Applied to u-boot/master, thanks!

This patch changes mt7629 to use the compatible platform SMP initialization method of linux kernel.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- arch/arm/mach-mediatek/mt7629/lowlevel_init.S | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-)
diff --git a/arch/arm/mach-mediatek/mt7629/lowlevel_init.S b/arch/arm/mach-mediatek/mt7629/lowlevel_init.S index 90dd4ea48e4..3375796b797 100644 --- a/arch/arm/mach-mediatek/mt7629/lowlevel_init.S +++ b/arch/arm/mach-mediatek/mt7629/lowlevel_init.S @@ -5,6 +5,14 @@
#include <linux/linkage.h>
+#define WAIT_CODE_SRAM_BASE 0x0010ff00 + +#define SLAVE_JUMP_REG 0x10202034 +#define SLAVE1_MAGIC_REG 0x10202038 +#define SLAVE1_MAGIC_NUM 0x534c4131 + +#define GIC_CPU_BASE 0x10320000 + ENTRY(lowlevel_init)
#ifndef CONFIG_SPL_BUILD @@ -28,6 +36,7 @@ ENTRY(lowlevel_init) mrc p15, 0, r0, c0, c0, 5 ands r1, r0, #0x40000000 bne go @ Go if UP + /* read slave CPU number */ ands r0, r0, #0x0f beq go @ Go if core0 on primary core tile b secondary @@ -37,14 +46,41 @@ go: mov pc, lr
secondary: - /* read slave CPU number into r0 firstly */ - mrc p15, 0, r0, c0, c0, 5 - and r0, r0, #0x0f + /* enable GIC as cores will be waken up by IPI */ + ldr r2, =GIC_CPU_BASE + mov r1, #0xf0 + str r1, [r2, #4] + mov r1, #1 + str r1, [r2, #0] + + ldr r1, [r2] + orr r1, #1 + str r1, [r2] + + /* copy wait code into SRAM */ + ldr r0, =slave_cpu_wait + ldm r0, {r1 - r8} @ slave_cpu_wait has eight insns + ldr r0, =WAIT_CODE_SRAM_BASE + stm r0, {r1 - r8} + + /* pass args to slave_cpu_wait */ + ldr r0, =SLAVE1_MAGIC_REG + ldr r1, =SLAVE1_MAGIC_NUM + + /* jump to wait code in SRAM */ + ldr pc, =WAIT_CODE_SRAM_BASE
-loop: - dsb - isb - wfi @Zzz... - b loop #endif ENDPROC(lowlevel_init) + +/* This function will be copied into SRAM */ +ENTRY(slave_cpu_wait) + wfi + ldr r2, [r0] + cmp r2, r1 + bne slave_cpu_wait + movw r0, #:lower16:SLAVE_JUMP_REG + movt r0, #:upper16:SLAVE_JUMP_REG + ldr r1, [r0] + mov pc, r1 +ENDPROC(slave_cpu_wait)

On Thu, Dec 20, 2018 at 04:12:50PM +0800, Weijie Gao wrote:
This patch changes mt7629 to use the compatible platform SMP initialization method of linux kernel.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
Applied to u-boot/master, thanks!

This patch adds reset controller driver for MediaTek SoCs.
Signed-off-by: Ryder Lee ryder.lee@mediatek.com Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- arch/arm/include/asm/arch-mediatek/reset.h | 13 +++ drivers/reset/Kconfig | 7 ++ drivers/reset/Makefile | 1 + drivers/reset/reset-mediatek.c | 102 +++++++++++++++++++++ include/dt-bindings/reset/mtk-reset.h | 18 ++++ 5 files changed, 141 insertions(+) create mode 100644 arch/arm/include/asm/arch-mediatek/reset.h create mode 100644 drivers/reset/reset-mediatek.c create mode 100644 include/dt-bindings/reset/mtk-reset.h
diff --git a/arch/arm/include/asm/arch-mediatek/reset.h b/arch/arm/include/asm/arch-mediatek/reset.h new file mode 100644 index 00000000000..9704666d24e --- /dev/null +++ b/arch/arm/include/asm/arch-mediatek/reset.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MediaTek Inc. + */ + +#ifndef __MEDIATEK_RESET_H +#define __MEDIATEK_RESET_H + +#include <dm.h> + +int mediatek_reset_bind(struct udevice *pdev, u32 regofs, u32 num_regs); + +#endif /* __MEDIATEK_RESET_H */ diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 9c5208b7da5..3a6d61f440c 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -106,4 +106,11 @@ config RESET_SOCFPGA help Support for reset controller on SoCFPGA platform.
+config RESET_MEDIATEK + bool "Reset controller driver for MediaTek SoCs" + depends on DM_RESET && ARCH_MEDIATEK && CLK + default y + help + Support for reset controller on MediaTek SoCs. + endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index f4520878b7c..8a4dcab8f64 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_AST2500_RESET) += ast2500-reset.o obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o +obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.o diff --git a/drivers/reset/reset-mediatek.c b/drivers/reset/reset-mediatek.c new file mode 100644 index 00000000000..e3614e6e2ae --- /dev/null +++ b/drivers/reset/reset-mediatek.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: Ryder Lee ryder.lee@mediatek.com + * Weijie Gao weijie.gao@mediatek.com + */ + +#include <common.h> +#include <dm.h> +#include <dm/lists.h> +#include <regmap.h> +#include <reset-uclass.h> +#include <syscon.h> + +struct mediatek_reset_priv { + struct regmap *regmap; + u32 regofs; + u32 nr_resets; +}; + +static int mediatek_reset_request(struct reset_ctl *reset_ctl) +{ + return 0; +} + +static int mediatek_reset_free(struct reset_ctl *reset_ctl) +{ + return 0; +} + +static int mediatek_reset_assert(struct reset_ctl *reset_ctl) +{ + struct mediatek_reset_priv *priv = dev_get_priv(reset_ctl->dev); + int id = reset_ctl->id; + + if (id >= priv->nr_resets) + return -EINVAL; + + return regmap_update_bits(priv->regmap, + priv->regofs + ((id / 32) << 2), BIT(id % 32), BIT(id % 32)); +} + +static int mediatek_reset_deassert(struct reset_ctl *reset_ctl) +{ + struct mediatek_reset_priv *priv = dev_get_priv(reset_ctl->dev); + int id = reset_ctl->id; + + if (id >= priv->nr_resets) + return -EINVAL; + + return regmap_update_bits(priv->regmap, + priv->regofs + ((id / 32) << 2), BIT(id % 32), 0); +} + +struct reset_ops mediatek_reset_ops = { + .request = mediatek_reset_request, + .free = mediatek_reset_free, + .rst_assert = mediatek_reset_assert, + .rst_deassert = mediatek_reset_deassert, +}; + +static int mediatek_reset_probe(struct udevice *dev) +{ + struct mediatek_reset_priv *priv = dev_get_priv(dev); + + if (!priv->regofs && !priv->nr_resets) + return -EINVAL; + + priv->regmap = syscon_node_to_regmap(dev_ofnode(dev)); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + return 0; +} + +int mediatek_reset_bind(struct udevice *pdev, u32 regofs, u32 num_regs) +{ + struct udevice *rst_dev; + struct mediatek_reset_priv *priv; + int ret; + + ret = device_bind_driver_to_node(pdev, "mediatek_reset", "reset", + dev_ofnode(pdev), &rst_dev); + if (ret) + return ret; + + priv = malloc(sizeof(struct mediatek_reset_priv)); + priv->regofs = regofs; + priv->nr_resets = num_regs * 32; + rst_dev->priv = priv; + + return 0; +} + +U_BOOT_DRIVER(mediatek_reset) = { + .name = "mediatek_reset", + .id = UCLASS_RESET, + .probe = mediatek_reset_probe, + .ops = &mediatek_reset_ops, + .priv_auto_alloc_size = sizeof(struct mediatek_reset_priv), +}; diff --git a/include/dt-bindings/reset/mtk-reset.h b/include/dt-bindings/reset/mtk-reset.h new file mode 100644 index 00000000000..5f0a74f280c --- /dev/null +++ b/include/dt-bindings/reset/mtk-reset.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MediaTek Inc. + */ + +#ifndef _DT_BINDINGS_MTK_RESET_H_ +#define _DT_BINDINGS_MTK_RESET_H_ + +/* ETHSYS */ +#define ETHSYS_PPE_RST 31 +#define ETHSYS_EPHY_RST 24 +#define ETHSYS_GMAC_RST 23 +#define ETHSYS_ESW_RST 16 +#define ETHSYS_FE_RST 6 +#define ETHSYS_MCM_RST 2 +#define ETHSYS_SYS_RST 0 + +#endif /* _DT_BINDINGS_MTK_RESET_H_ */

Hi,
here you have a small typo in commit-Message (Subject) "MedaiTek:"
as of Tom tells me there is a problem with SMP-Initialisation, you may need a v2 and can fix this typo
regards Frank

On Thu, Dec 20, 2018 at 04:12:51PM +0800, Weijie Gao wrote:
This patch adds reset controller driver for MediaTek SoCs.
Signed-off-by: Ryder Lee ryder.lee@mediatek.com Signed-off-by: Weijie Gao weijie.gao@mediatek.com
Applied to u-boot/master, thanks!

The ethsys contains not only the clock gating controller, but also the reset controller for the whole ethernet subsystem and its components.
This patch adds binding of the reset controller so that the ethernet node can have references on it.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- drivers/clk/mediatek/clk-mt7623.c | 15 +++++++++++++++ drivers/clk/mediatek/clk-mt7629.c | 15 +++++++++++++++ drivers/clk/mediatek/clk-mtk.h | 2 ++ 3 files changed, 32 insertions(+)
diff --git a/drivers/clk/mediatek/clk-mt7623.c b/drivers/clk/mediatek/clk-mt7623.c index c6b09d8e18d..87ad4f79ced 100644 --- a/drivers/clk/mediatek/clk-mt7623.c +++ b/drivers/clk/mediatek/clk-mt7623.c @@ -8,6 +8,7 @@
#include <common.h> #include <dm.h> +#include <asm/arch-mediatek/reset.h> #include <asm/io.h> #include <dt-bindings/clock/mt7623-clk.h>
@@ -782,6 +783,19 @@ static int mt7623_ethsys_probe(struct udevice *dev) return mtk_common_clk_gate_init(dev, &mt7623_clk_tree, eth_cgs); }
+static int mt7623_ethsys_bind(struct udevice *dev) +{ + int ret = 0; + +#if CONFIG_IS_ENABLED(RESET_MEDIATEK) + ret = mediatek_reset_bind(dev, ETHSYS_RST_CTRL_OFS, 1); + if (ret) + debug("Warning: failed to bind ethsys reset controller\n"); +#endif + + return ret; +} + static const struct udevice_id mt7623_apmixed_compat[] = { { .compatible = "mediatek,mt7623-apmixedsys" }, { } @@ -865,6 +879,7 @@ U_BOOT_DRIVER(mtk_clk_ethsys) = { .id = UCLASS_CLK, .of_match = mt7623_ethsys_compat, .probe = mt7623_ethsys_probe, + .bind = mt7623_ethsys_bind, .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), .ops = &mtk_clk_gate_ops, }; diff --git a/drivers/clk/mediatek/clk-mt7629.c b/drivers/clk/mediatek/clk-mt7629.c index 2601b6cf30d..6a9f60139c0 100644 --- a/drivers/clk/mediatek/clk-mt7629.c +++ b/drivers/clk/mediatek/clk-mt7629.c @@ -8,6 +8,7 @@
#include <common.h> #include <dm.h> +#include <asm/arch-mediatek/reset.h> #include <asm/io.h> #include <dt-bindings/clock/mt7629-clk.h>
@@ -602,6 +603,19 @@ static int mt7629_ethsys_probe(struct udevice *dev) return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, eth_cgs); }
+static int mt7629_ethsys_bind(struct udevice *dev) +{ + int ret = 0; + +#if CONFIG_IS_ENABLED(RESET_MEDIATEK) + ret = mediatek_reset_bind(dev, ETHSYS_RST_CTRL_OFS, 1); + if (ret) + debug("Warning: failed to bind ethsys reset controller\n"); +#endif + + return ret; +} + static int mt7629_sgmiisys_probe(struct udevice *dev) { return mtk_common_clk_gate_init(dev, &mt7629_clk_tree, sgmii_cgs); @@ -695,6 +709,7 @@ U_BOOT_DRIVER(mtk_clk_ethsys) = { .id = UCLASS_CLK, .of_match = mt7629_ethsys_compat, .probe = mt7629_ethsys_probe, + .bind = mt7629_ethsys_bind, .priv_auto_alloc_size = sizeof(struct mtk_cg_priv), .ops = &mtk_clk_gate_ops, }; diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index 74152ed9c6e..7847388b2a1 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -23,6 +23,8 @@ #define CLK_PARENT_TOPCKGEN BIT(5) #define CLK_PARENT_MASK GENMASK(5, 4)
+#define ETHSYS_RST_CTRL_OFS 0x34 + /* struct mtk_pll_data - hardware-specific PLLs data */ struct mtk_pll_data { const int id;

On Thu, Dec 20, 2018 at 04:12:52PM +0800, Weijie Gao wrote:
The ethsys contains not only the clock gating controller, but also the reset controller for the whole ethernet subsystem and its components.
This patch adds binding of the reset controller so that the ethernet node can have references on it.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
Applied to u-boot/master, thanks!

This patch adds ethernet support for Mediatek ARM-based SoCs, including a minimum setup of the integrated switch.
Cc: Joe Hershberger joe.hershberger@ni.com Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- drivers/net/Kconfig | 10 + drivers/net/Makefile | 1 + drivers/net/mtk_eth.c | 1175 +++++++++++++++++++++++++++++++++++++++++ drivers/net/mtk_eth.h | 286 ++++++++++ 4 files changed, 1472 insertions(+) create mode 100644 drivers/net/mtk_eth.c create mode 100644 drivers/net/mtk_eth.h
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8fb365fc5d2..470aa8d0b9e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -495,4 +495,14 @@ config TSEC_ENET This driver implements support for the (Enhanced) Three-Speed Ethernet Controller found on Freescale SoCs.
+config MEDIATEK_ETH + bool "MediaTek Ethernet GMAC Driver" + depends on DM_ETH + select PHYLIB + select DM_GPIO + select DM_RESET + help + This Driver support MediaTek Ethernet GMAC + Say Y to enable support for the MediaTek Ethernet GMAC. + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 99056aa041d..f3740a6fe1d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -72,3 +72,4 @@ obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o obj-$(CONFIG_FSL_PFE) += pfe_eth/ obj-$(CONFIG_SNI_AVE) += sni_ave.o obj-y += ti/ +obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c new file mode 100644 index 00000000000..cc09404830a --- /dev/null +++ b/drivers/net/mtk_eth.c @@ -0,0 +1,1175 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: Weijie Gao weijie.gao@mediatek.com + * Author: Mark Lee mark-mc.lee@mediatek.com + */ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <miiphy.h> +#include <regmap.h> +#include <reset.h> +#include <syscon.h> +#include <wait_bit.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <linux/err.h> +#include <linux/ioport.h> +#include <linux/mdio.h> +#include <linux/mii.h> + +#include "mtk_eth.h" + +#define NUM_TX_DESC 24 +#define NUM_RX_DESC 24 +#define TX_TOTAL_BUF_SIZE (NUM_TX_DESC * PKTSIZE_ALIGN) +#define RX_TOTAL_BUF_SIZE (NUM_RX_DESC * PKTSIZE_ALIGN) +#define TOTAL_PKT_BUF_SIZE (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE) + +#define MT7530_NUM_PHYS 5 +#define MT7530_DFL_SMI_ADDR 31 + +#define MT7530_PHY_ADDR(base, addr) \ + (((base) + (addr)) & 0x1f) + +#define GDMA_FWD_TO_CPU \ + (0x20000000 | \ + GDM_ICS_EN | \ + GDM_TCS_EN | \ + GDM_UCS_EN | \ + STRP_CRC | \ + (DP_PDMA << MYMAC_DP_S) | \ + (DP_PDMA << BC_DP_S) | \ + (DP_PDMA << MC_DP_S) | \ + (DP_PDMA << UN_DP_S)) + +#define GDMA_FWD_DISCARD \ + (0x20000000 | \ + GDM_ICS_EN | \ + GDM_TCS_EN | \ + GDM_UCS_EN | \ + STRP_CRC | \ + (DP_DISCARD << MYMAC_DP_S) | \ + (DP_DISCARD << BC_DP_S) | \ + (DP_DISCARD << MC_DP_S) | \ + (DP_DISCARD << UN_DP_S)) + +struct pdma_rxd_info1 { + u32 PDP0; +}; + +struct pdma_rxd_info2 { + u32 PLEN1 : 14; + u32 LS1 : 1; + u32 UN_USED : 1; + u32 PLEN0 : 14; + u32 LS0 : 1; + u32 DDONE : 1; +}; + +struct pdma_rxd_info3 { + u32 PDP1; +}; + +struct pdma_rxd_info4 { + u32 FOE_ENTRY : 14; + u32 CRSN : 5; + u32 SP : 3; + u32 L4F : 1; + u32 L4VLD : 1; + u32 TACK : 1; + u32 IP4F : 1; + u32 IP4 : 1; + u32 IP6 : 1; + u32 UN_USED : 4; +}; + +struct pdma_rxdesc { + struct pdma_rxd_info1 rxd_info1; + struct pdma_rxd_info2 rxd_info2; + struct pdma_rxd_info3 rxd_info3; + struct pdma_rxd_info4 rxd_info4; +}; + +struct pdma_txd_info1 { + u32 SDP0; +}; + +struct pdma_txd_info2 { + u32 SDL1 : 14; + u32 LS1 : 1; + u32 BURST : 1; + u32 SDL0 : 14; + u32 LS0 : 1; + u32 DDONE : 1; +}; + +struct pdma_txd_info3 { + u32 SDP1; +}; + +struct pdma_txd_info4 { + u32 VLAN_TAG : 16; + u32 INS : 1; + u32 RESV : 2; + u32 UDF : 6; + u32 FPORT : 3; + u32 TSO : 1; + u32 TUI_CO : 3; +}; + +struct pdma_txdesc { + struct pdma_txd_info1 txd_info1; + struct pdma_txd_info2 txd_info2; + struct pdma_txd_info3 txd_info3; + struct pdma_txd_info4 txd_info4; +}; + +enum mtk_switch { + SW_NONE, + SW_MT7530 +}; + +enum mtk_soc { + SOC_MT7623, + SOC_MT7629 +}; + +struct mtk_eth_priv { + char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN); + + struct pdma_txdesc *tx_ring_noc; + struct pdma_rxdesc *rx_ring_noc; + + int rx_dma_owner_idx0; + int tx_cpu_owner_idx0; + + void __iomem *fe_base; + void __iomem *gmac_base; + void __iomem *ethsys_base; + + struct mii_dev *mdio_bus; + int (*mii_read)(struct mtk_eth_priv *priv, u8 phy, u8 reg); + int (*mii_write)(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 val); + int (*mmd_read)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg); + int (*mmd_write)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg, + u16 val); + + enum mtk_soc soc; + int gmac_id; + int force_mode; + int speed; + int duplex; + + struct phy_device *phydev; + int phy_interface; + int phy_addr; + + enum mtk_switch sw; + int (*switch_init)(struct mtk_eth_priv *priv); + u32 mt7530_smi_addr; + u32 mt7530_phy_base; + + struct gpio_desc rst_gpio; + int mcm; + + struct reset_ctl rst_fe; + struct reset_ctl rst_mcm; +}; + +static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val) +{ + writel(val, priv->fe_base + PDMA_BASE + reg); +} + +static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, + u32 set) +{ + clrsetbits_le32(priv->fe_base + PDMA_BASE + reg, clr, set); +} + +static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg, + u32 val) +{ + u32 gdma_base; + + if (no == 1) + gdma_base = GDMA2_BASE; + else + gdma_base = GDMA1_BASE; + + writel(val, priv->fe_base + gdma_base + reg); +} + +static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg) +{ + return readl(priv->gmac_base + reg); +} + +static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val) +{ + writel(val, priv->gmac_base + reg); +} + +static void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set) +{ + clrsetbits_le32(priv->gmac_base + reg, clr, set); +} + +static void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, + u32 set) +{ + clrsetbits_le32(priv->ethsys_base + reg, clr, set); +} + +/* Direct MDIO clause 22/45 access via SoC */ +static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data, + u32 cmd, u32 st) +{ + int ret; + u32 val; + + val = (st << MDIO_ST_S) | + ((cmd << MDIO_CMD_S) & MDIO_CMD_M) | + (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) | + (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M); + + if (cmd == MDIO_CMD_WRITE) + val |= data & MDIO_RW_DATA_M; + + mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST); + + ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG, + PHY_ACS_ST, 0, 5000, 0); + if (ret) { + pr_warn("MDIO access timeout\n"); + return ret; + } + + if (cmd == MDIO_CMD_READ) { + val = mtk_gmac_read(priv, GMAC_PIAC_REG); + return val & MDIO_RW_DATA_M; + } + + return 0; +} + +/* Direct MDIO clause 22 read via SoC */ +static int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg) +{ + return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22); +} + +/* Direct MDIO clause 22 write via SoC */ +static int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data) +{ + return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22); +} + +/* Direct MDIO clause 45 read via SoC */ +static int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg) +{ + int ret; + + ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); + if (ret) + return ret; + + return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45, + MDIO_ST_C45); +} + +/* Direct MDIO clause 45 write via SoC */ +static int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, + u16 reg, u16 val) +{ + int ret; + + ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45); + if (ret) + return ret; + + return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE, + MDIO_ST_C45); +} + +/* Indirect MDIO clause 45 read via MII registers */ +static int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, + u16 reg) +{ + int ret; + + ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, + (MMD_ADDR << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); + if (ret) + return ret; + + ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg); + if (ret) + return ret; + + ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, + (MMD_DATA << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); + if (ret) + return ret; + + return priv->mii_read(priv, addr, MII_MMD_ADDR_DATA_REG); +} + +/* Indirect MDIO clause 45 write via MII registers */ +static int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, + u16 reg, u16 val) +{ + int ret; + + ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, + (MMD_ADDR << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); + if (ret) + return ret; + + ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg); + if (ret) + return ret; + + ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG, + (MMD_DATA << MMD_CMD_S) | + ((devad << MMD_DEVAD_S) & MMD_DEVAD_M)); + if (ret) + return ret; + + return priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val); +} + +static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mtk_eth_priv *priv = bus->priv; + + if (devad < 0) + return priv->mii_read(priv, addr, reg); + else + return priv->mmd_read(priv, addr, devad, reg); +} + +static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, + u16 val) +{ + struct mtk_eth_priv *priv = bus->priv; + + if (devad < 0) + return priv->mii_write(priv, addr, reg, val); + else + return priv->mmd_write(priv, addr, devad, reg, val); +} + +static int mtk_mdio_register(struct udevice *dev) +{ + struct mtk_eth_priv *priv = dev_get_priv(dev); + struct mii_dev *mdio_bus = mdio_alloc(); + int ret; + + if (!mdio_bus) + return -ENOMEM; + + /* Assign MDIO access APIs according to the switch/phy */ + switch (priv->sw) { + case SW_MT7530: + priv->mii_read = mtk_mii_read; + priv->mii_write = mtk_mii_write; + priv->mmd_read = mtk_mmd_ind_read; + priv->mmd_write = mtk_mmd_ind_write; + break; + default: + priv->mii_read = mtk_mii_read; + priv->mii_write = mtk_mii_write; + priv->mmd_read = mtk_mmd_read; + priv->mmd_write = mtk_mmd_write; + } + + mdio_bus->read = mtk_mdio_read; + mdio_bus->write = mtk_mdio_write; + snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name); + + mdio_bus->priv = (void *)priv; + + ret = mdio_register(mdio_bus); + + if (ret) + return ret; + + priv->mdio_bus = mdio_bus; + + return 0; +} + +/* + * MT7530 Internal Register Address Bits + * ------------------------------------------------------------------- + * | 15 14 13 12 11 10 9 8 7 6 | 5 4 3 2 | 1 0 | + * |----------------------------------------|---------------|--------| + * | Page Address | Reg Address | Unused | + * ------------------------------------------------------------------- + */ + +static int mt7530_reg_read(struct mtk_eth_priv *priv, u32 reg, u32 *data) +{ + int ret, low_word, high_word; + + /* Write page address */ + ret = mtk_mii_write(priv, priv->mt7530_smi_addr, 0x1f, reg >> 6); + if (ret) + return ret; + + /* Read low word */ + low_word = mtk_mii_read(priv, priv->mt7530_smi_addr, (reg >> 2) & 0xf); + if (low_word < 0) + return low_word; + + /* Read high word */ + high_word = mtk_mii_read(priv, priv->mt7530_smi_addr, 0x10); + if (high_word < 0) + return high_word; + + if (data) + *data = ((u32)high_word << 16) | (low_word & 0xffff); + + return 0; +} + +static int mt7530_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 data) +{ + int ret; + + /* Write page address */ + ret = mtk_mii_write(priv, priv->mt7530_smi_addr, 0x1f, reg >> 6); + if (ret) + return ret; + + /* Write low word */ + ret = mtk_mii_write(priv, priv->mt7530_smi_addr, (reg >> 2) & 0xf, + data & 0xffff); + if (ret) + return ret; + + /* Write high word */ + return mtk_mii_write(priv, priv->mt7530_smi_addr, 0x10, data >> 16); +} + +static void mt7530_reg_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, + u32 set) +{ + u32 val; + + mt7530_reg_read(priv, reg, &val); + val &= ~clr; + val |= set; + mt7530_reg_write(priv, reg, val); +} + +static void mt7530_core_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 val) +{ + u8 phy_addr = MT7530_PHY_ADDR(priv->mt7530_phy_base, 0); + + mtk_mmd_ind_write(priv, phy_addr, 0x1f, reg, val); +} + +static int mt7530_pad_clk_setup(struct mtk_eth_priv *priv, int mode) +{ + u32 ncpo1, ssc_delta; + + switch (mode) { + case PHY_INTERFACE_MODE_RGMII: + ncpo1 = 0x0c80; + ssc_delta = 0x87; + break; + default: + printf("error: xMII mode %d not supported\n", mode); + return -EINVAL; + } + + /* Disable MT7530 core clock */ + mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0); + + /* Disable MT7530 PLL */ + mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1, + (2 << RG_GSWPLL_POSDIV_200M_S) | + (32 << RG_GSWPLL_FBKDIV_200M_S)); + + /* For MT7530 core clock = 500Mhz */ + mt7530_core_reg_write(priv, CORE_GSWPLL_GRP2, + (1 << RG_GSWPLL_POSDIV_500M_S) | + (25 << RG_GSWPLL_FBKDIV_500M_S)); + + /* Enable MT7530 PLL */ + mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1, + (2 << RG_GSWPLL_POSDIV_200M_S) | + (32 << RG_GSWPLL_FBKDIV_200M_S) | + RG_GSWPLL_EN_PRE); + + udelay(20); + + mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN); + + /* Setup the MT7530 TRGMII Tx Clock */ + mt7530_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1); + mt7530_core_reg_write(priv, CORE_PLL_GROUP6, 0); + mt7530_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta); + mt7530_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta); + mt7530_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN | + RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN); + + mt7530_core_reg_write(priv, CORE_PLL_GROUP2, + RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN | + (1 << RG_SYSPLL_POSDIV_S)); + + mt7530_core_reg_write(priv, CORE_PLL_GROUP7, + RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) | + RG_LCDDS_PWDB | RG_LCDDS_ISO_EN); + + /* Enable MT7530 core clock */ + mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, + REG_GSWCK_EN | REG_TRGMIICK_EN); + + return 0; +} + +static int mt7530_setup(struct mtk_eth_priv *priv) +{ + u16 phy_addr, phy_val; + u32 val; + int i; + + /* Select 250MHz clk for RGMII mode */ + mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG, + ETHSYS_TRGMII_CLK_SEL362_5, 0); + + /* Global reset switch */ + if (priv->mcm) { + reset_assert(&priv->rst_mcm); + udelay(1000); + reset_deassert(&priv->rst_mcm); + mdelay(1000); + } else if (dm_gpio_is_valid(&priv->rst_gpio)) { + dm_gpio_set_value(&priv->rst_gpio, 0); + udelay(1000); + dm_gpio_set_value(&priv->rst_gpio, 1); + mdelay(1000); + } + + /* Modify HWTRAP first to allow direct access to internal PHYs */ + mt7530_reg_read(priv, HWTRAP_REG, &val); + val |= CHG_TRAP; + val &= ~C_MDIO_BPS; + mt7530_reg_write(priv, MHWTRAP_REG, val); + + /* Calculate the phy base address */ + val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3; + priv->mt7530_phy_base = (val | 0x7) + 1; + + /* Turn off PHYs */ + for (i = 0; i < MT7530_NUM_PHYS; i++) { + phy_addr = MT7530_PHY_ADDR(priv->mt7530_phy_base, i); + phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); + phy_val |= BMCR_PDOWN; + priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); + } + + /* Force MAC link down before reset */ + mt7530_reg_write(priv, PCMR_REG(5), FORCE_MODE); + mt7530_reg_write(priv, PCMR_REG(6), FORCE_MODE); + + /* MT7530 reset */ + mt7530_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST); + udelay(100); + + val = (1 << IPG_CFG_S) | + MAC_MODE | FORCE_MODE | + MAC_TX_EN | MAC_RX_EN | + BKOFF_EN | BACKPR_EN | + (SPEED_1000M << FORCE_SPD_S) | + FORCE_DPX | FORCE_LINK; + + /* MT7530 Port6: Forced 1000M/FD, FC disabled */ + mt7530_reg_write(priv, PCMR_REG(6), val); + + /* MT7530 Port5: Forced link down */ + mt7530_reg_write(priv, PCMR_REG(5), FORCE_MODE); + + /* MT7530 Port6: Set to RGMII */ + mt7530_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII); + + /* Hardware Trap: Enable Port6, Disable Port5 */ + mt7530_reg_read(priv, HWTRAP_REG, &val); + val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS | + (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) | + (P5_INTF_MODE_RGMII << P5_INTF_MODE_S); + val &= ~(C_MDIO_BPS | P6_INTF_DIS); + mt7530_reg_write(priv, MHWTRAP_REG, val); + + /* Setup switch core pll */ + mt7530_pad_clk_setup(priv, priv->phy_interface); + + /* Lower Tx Driving for TRGMII path */ + for (i = 0 ; i < NUM_TRGMII_CTRL ; i++) + mt7530_reg_write(priv, MT7530_TRGMII_TD_ODT(i), + (8 << TD_DM_DRVP_S) | (8 << TD_DM_DRVN_S)); + + for (i = 0 ; i < NUM_TRGMII_CTRL; i++) + mt7530_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16); + + /* Turn on PHYs */ + for (i = 0; i < MT7530_NUM_PHYS; i++) { + phy_addr = MT7530_PHY_ADDR(priv->mt7530_phy_base, i); + phy_val = priv->mii_read(priv, phy_addr, MII_BMCR); + phy_val &= ~BMCR_PDOWN; + priv->mii_write(priv, phy_addr, MII_BMCR, phy_val); + } + + /* Set port isolation */ + for (i = 0; i < 8; i++) { + /* Set port matrix mode */ + if (i != 6) + mt7530_reg_write(priv, PCR_REG(i), + (0x40 << PORT_MATRIX_S)); + else + mt7530_reg_write(priv, PCR_REG(i), + (0x3f << PORT_MATRIX_S)); + + /* Set port mode to user port */ + mt7530_reg_write(priv, PVC_REG(i), + (0x8100 << STAG_VPID_S) | + (VLAN_ATTR_USER << VLAN_ATTR_S)); + } + + return 0; +} + +static void mtk_phy_link_adjust(struct mtk_eth_priv *priv) +{ + u16 lcl_adv = 0, rmt_adv = 0; + u8 flowctrl; + u32 mcr; + + mcr = (1 << IPG_CFG_S) | + (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) | + MAC_MODE | FORCE_MODE | + MAC_TX_EN | MAC_RX_EN | + BKOFF_EN | BACKPR_EN; + + switch (priv->phydev->speed) { + case SPEED_10: + mcr |= (SPEED_10M << FORCE_SPD_S); + break; + case SPEED_100: + mcr |= (SPEED_100M << FORCE_SPD_S); + break; + case SPEED_1000: + mcr |= (SPEED_1000M << FORCE_SPD_S); + break; + }; + + if (priv->phydev->link) + mcr |= FORCE_LINK; + + if (priv->phydev->duplex) { + mcr |= FORCE_DPX; + + if (priv->phydev->pause) + rmt_adv = LPA_PAUSE_CAP; + if (priv->phydev->asym_pause) + rmt_adv |= LPA_PAUSE_ASYM; + + if (priv->phydev->advertising & ADVERTISED_Pause) + lcl_adv |= ADVERTISE_PAUSE_CAP; + if (priv->phydev->advertising & ADVERTISED_Asym_Pause) + lcl_adv |= ADVERTISE_PAUSE_ASYM; + + flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); + + if (flowctrl & FLOW_CTRL_TX) + mcr |= FORCE_TX_FC; + if (flowctrl & FLOW_CTRL_RX) + mcr |= FORCE_RX_FC; + + debug("rx pause %s, tx pause %s\n", + flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled", + flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled"); + } + + mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr); +} + +static int mtk_phy_start(struct mtk_eth_priv *priv) +{ + struct phy_device *phydev = priv->phydev; + int ret; + + ret = phy_startup(phydev); + + if (ret) { + debug("Could not initialize PHY %s\n", phydev->dev->name); + return ret; + } + + if (!phydev->link) { + debug("%s: link down.\n", phydev->dev->name); + return 0; + } + + mtk_phy_link_adjust(priv); + + debug("Speed: %d, %s duplex%s\n", phydev->speed, + (phydev->duplex) ? "full" : "half", + (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); + + return 0; +} + +static int mtk_phy_probe(struct udevice *dev) +{ + struct mtk_eth_priv *priv = dev_get_priv(dev); + struct phy_device *phydev; + + phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev, + priv->phy_interface); + if (!phydev) + return -ENODEV; + + phydev->supported &= PHY_GBIT_FEATURES; + phydev->advertising = phydev->supported; + + priv->phydev = phydev; + phy_config(phydev); + + return 0; +} + +static void mtk_mac_init(struct mtk_eth_priv *priv) +{ + int i, ge_mode = 0; + u32 mcr; + + switch (priv->phy_interface) { + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_SGMII: + ge_mode = GE_MODE_RGMII; + break; + case PHY_INTERFACE_MODE_MII: + case PHY_INTERFACE_MODE_GMII: + ge_mode = GE_MODE_MII; + break; + case PHY_INTERFACE_MODE_RMII: + ge_mode = GE_MODE_RMII; + break; + default: + break; + } + + /* set the gmac to the right mode */ + mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG, + SYSCFG0_GE_MODE_M << SYSCFG0_GE_MODE_S(priv->gmac_id), + ge_mode << SYSCFG0_GE_MODE_S(priv->gmac_id)); + + if (priv->force_mode) { + mcr = (1 << IPG_CFG_S) | + (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) | + MAC_MODE | FORCE_MODE | + MAC_TX_EN | MAC_RX_EN | + BKOFF_EN | BACKPR_EN | + FORCE_LINK; + + switch (priv->speed) { + case SPEED_10: + mcr |= SPEED_10M << FORCE_SPD_S; + break; + case SPEED_100: + mcr |= SPEED_100M << FORCE_SPD_S; + break; + case SPEED_1000: + mcr |= SPEED_1000M << FORCE_SPD_S; + break; + } + + if (priv->duplex) + mcr |= FORCE_DPX; + + mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr); + } + + if (priv->soc == SOC_MT7623) { + /* Lower Tx Driving for TRGMII path */ + for (i = 0 ; i < NUM_TRGMII_CTRL; i++) + mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i), + (8 << TD_DM_DRVP_S) | + (8 << TD_DM_DRVN_S)); + + mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0, + RX_RST | RXC_DQSISEL); + mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0); + } +} + +static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) +{ + char *pkt_base = priv->pkt_pool; + int i; + + mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0); + udelay(500); + + memset(priv->tx_ring_noc, 0, NUM_TX_DESC * sizeof(struct pdma_txdesc)); + memset(priv->rx_ring_noc, 0, NUM_RX_DESC * sizeof(struct pdma_rxdesc)); + memset(priv->pkt_pool, 0, TOTAL_PKT_BUF_SIZE); + + flush_dcache_range((u32)pkt_base, (u32)(pkt_base + TOTAL_PKT_BUF_SIZE)); + + priv->rx_dma_owner_idx0 = 0; + priv->tx_cpu_owner_idx0 = 0; + + for (i = 0; i < NUM_TX_DESC; i++) { + priv->tx_ring_noc[i].txd_info2.LS0 = 1; + priv->tx_ring_noc[i].txd_info2.DDONE = 1; + priv->tx_ring_noc[i].txd_info4.FPORT = priv->gmac_id + 1; + + priv->tx_ring_noc[i].txd_info1.SDP0 = virt_to_phys(pkt_base); + pkt_base += PKTSIZE_ALIGN; + } + + for (i = 0; i < NUM_RX_DESC; i++) { + priv->rx_ring_noc[i].rxd_info2.PLEN0 = PKTSIZE_ALIGN; + priv->rx_ring_noc[i].rxd_info1.PDP0 = virt_to_phys(pkt_base); + pkt_base += PKTSIZE_ALIGN; + } + + mtk_pdma_write(priv, TX_BASE_PTR_REG(0), + virt_to_phys(priv->tx_ring_noc)); + mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC); + mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0); + + mtk_pdma_write(priv, RX_BASE_PTR_REG(0), + virt_to_phys(priv->rx_ring_noc)); + mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC); + mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1); + + mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0); +} + +static int mtk_eth_start(struct udevice *dev) +{ + struct mtk_eth_priv *priv = dev_get_priv(dev); + int ret; + + /* Reset FE */ + reset_assert(&priv->rst_fe); + udelay(1000); + reset_deassert(&priv->rst_fe); + mdelay(10); + + /* Packets forward to PDMA */ + mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU); + + if (priv->gmac_id == 0) + mtk_gdma_write(priv, 1, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD); + else + mtk_gdma_write(priv, 0, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD); + + udelay(500); + + mtk_eth_fifo_init(priv); + + /* Start PHY */ + if (priv->sw == SW_NONE) { + ret = mtk_phy_start(priv); + if (ret) + return ret; + } + + mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0, + TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN); + udelay(500); + + return 0; +} + +static void mtk_eth_stop(struct udevice *dev) +{ + struct mtk_eth_priv *priv = dev_get_priv(dev); + + mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, + TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0); + udelay(500); + + wait_for_bit_le32(priv->fe_base + PDMA_BASE + PDMA_GLO_CFG_REG, + RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0); +} + +static int mtk_eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct mtk_eth_priv *priv = dev_get_priv(dev); + unsigned char *mac = pdata->enetaddr; + u32 macaddr_lsb, macaddr_msb; + + macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1]; + macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) | + ((u32)mac[4] << 8) | (u32)mac[5]; + + mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb); + mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb); + + return 0; +} + +static int mtk_eth_send(struct udevice *dev, void *packet, int length) +{ + struct mtk_eth_priv *priv = dev_get_priv(dev); + u32 idx = priv->tx_cpu_owner_idx0; + void *pkt_base; + + if (!priv->tx_ring_noc[idx].txd_info2.DDONE) { + debug("mtk-eth: TX DMA descriptor ring is full\n"); + return -EPERM; + } + + pkt_base = (void *)phys_to_virt(priv->tx_ring_noc[idx].txd_info1.SDP0); + memcpy(pkt_base, packet, length); + flush_dcache_range((u32)pkt_base, (u32)pkt_base + + roundup(length, ARCH_DMA_MINALIGN)); + + priv->tx_ring_noc[idx].txd_info2.SDL0 = length; + priv->tx_ring_noc[idx].txd_info2.DDONE = 0; + + priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC; + mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0); + + return 0; +} + +static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct mtk_eth_priv *priv = dev_get_priv(dev); + u32 idx = priv->rx_dma_owner_idx0; + uchar *pkt_base; + u32 length; + + if (!priv->rx_ring_noc[idx].rxd_info2.DDONE) { + debug("mtk-eth: RX DMA descriptor ring is empty\n"); + return -EAGAIN; + } + + length = priv->rx_ring_noc[idx].rxd_info2.PLEN0; + pkt_base = (void *)phys_to_virt(priv->rx_ring_noc[idx].rxd_info1.PDP0); + invalidate_dcache_range((u32)pkt_base, (u32)pkt_base + + roundup(length, ARCH_DMA_MINALIGN)); + + if (packetp) + *packetp = pkt_base; + + return length; +} + +static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct mtk_eth_priv *priv = dev_get_priv(dev); + u32 idx = priv->rx_dma_owner_idx0; + + priv->rx_ring_noc[idx].rxd_info2.DDONE = 0; + priv->rx_ring_noc[idx].rxd_info2.LS0 = 0; + priv->rx_ring_noc[idx].rxd_info2.PLEN0 = PKTSIZE_ALIGN; + + mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx); + priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC; + + return 0; +} + +static int mtk_eth_probe(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct mtk_eth_priv *priv = dev_get_priv(dev); + u32 iobase = pdata->iobase; + int ret; + + /* Frame Engine Register Base */ + priv->fe_base = (void *)iobase; + + /* GMAC Register Base */ + priv->gmac_base = (void *)(iobase + GMAC_BASE); + + /* MDIO register */ + ret = mtk_mdio_register(dev); + if (ret) + return ret; + + /* Prepare for tx/rx rings */ + priv->tx_ring_noc = (struct pdma_txdesc *) + noncached_alloc(sizeof(struct pdma_txdesc) * NUM_TX_DESC, + ARCH_DMA_MINALIGN); + priv->rx_ring_noc = (struct pdma_rxdesc *) + noncached_alloc(sizeof(struct pdma_rxdesc) * NUM_RX_DESC, + ARCH_DMA_MINALIGN); + + /* Set MAC mode */ + mtk_mac_init(priv); + + /* Probe phy if switch is not specified */ + if (priv->sw == SW_NONE) + return mtk_phy_probe(dev); + + /* Initialize switch */ + return priv->switch_init(priv); +} + +static int mtk_eth_remove(struct udevice *dev) +{ + struct mtk_eth_priv *priv = dev_get_priv(dev); + + /* MDIO unregister */ + mdio_unregister(priv->mdio_bus); + mdio_free(priv->mdio_bus); + + /* Stop possibly started DMA */ + mtk_eth_stop(dev); + + return 0; +} + +static int mtk_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct mtk_eth_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args args; + struct regmap *regmap; + const char *str; + ofnode subnode; + int ret; + + priv->soc = dev_get_driver_data(dev); + + pdata->iobase = devfdt_get_addr(dev); + + /* get corresponding ethsys phandle */ + ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0, + &args); + if (ret) + return ret; + + regmap = syscon_node_to_regmap(args.node); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + priv->ethsys_base = regmap_get_range(regmap, 0); + if (!priv->ethsys_base) { + dev_err(dev, "Unable to find ethsys\n"); + return -ENODEV; + } + + /* Reset controllers */ + ret = reset_get_by_name(dev, "fe", &priv->rst_fe); + if (ret) { + printf("error: Unable to get reset ctrl for frame engine\n"); + return ret; + } + + priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0); + + /* Interface mode is required */ + str = dev_read_string(dev, "phy-mode"); + if (str) { + pdata->phy_interface = phy_get_interface_by_name(str); + priv->phy_interface = pdata->phy_interface; + } else { + printf("error: phy-mode is not set\n"); + return -EINVAL; + } + + /* Force mode or autoneg */ + subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link"); + if (ofnode_valid(subnode)) { + priv->force_mode = 1; + priv->speed = ofnode_read_u32_default(subnode, "speed", 0); + priv->duplex = ofnode_read_bool(subnode, "full-duplex"); + + if (priv->speed != SPEED_10 && priv->speed != SPEED_100 && + priv->speed != SPEED_1000) { + printf("error: no valid speed set in fixed-link\n"); + return -EINVAL; + } + } + + /* check for switch first, otherwise phy will be used */ + priv->sw = SW_NONE; + priv->switch_init = NULL; + str = dev_read_string(dev, "mediatek,switch"); + + if (str) { + if (!strcmp(str, "mt7530")) { + priv->sw = SW_MT7530; + priv->switch_init = mt7530_setup; + priv->mt7530_smi_addr = MT7530_DFL_SMI_ADDR; + } else { + printf("error: unsupported switch\n"); + return -EINVAL; + } + + priv->mcm = dev_read_bool(dev, "mediatek,mcm"); + if (priv->mcm) { + ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm); + if (ret) { + printf("error: no reset ctrl for mcm\n"); + return ret; + } + } else { + gpio_request_by_name(dev, "reset-gpios", 0, + &priv->rst_gpio, GPIOD_IS_OUT); + } + } else { + subnode = ofnode_find_subnode(dev_ofnode(dev), "phy-handle"); + if (!ofnode_valid(subnode)) { + printf("error: phy-handle is not specified\n"); + return ret; + } + + priv->phy_addr = ofnode_read_s32_default(subnode, "reg", -1); + if (priv->phy_addr < 0) { + printf("error: phy address is not specified\n"); + return ret; + } + } + + return 0; +} + +static const struct udevice_id mtk_eth_ids[] = { + { .compatible = "mediatek,mt7629-eth", .data = SOC_MT7629 }, + { .compatible = "mediatek,mt7623-eth", .data = SOC_MT7623 }, + {} +}; + +static const struct eth_ops mtk_eth_ops = { + .start = mtk_eth_start, + .stop = mtk_eth_stop, + .send = mtk_eth_send, + .recv = mtk_eth_recv, + .free_pkt = mtk_eth_free_pkt, + .write_hwaddr = mtk_eth_write_hwaddr, +}; + +U_BOOT_DRIVER(mtk_eth) = { + .name = "mtk-eth", + .id = UCLASS_ETH, + .of_match = mtk_eth_ids, + .ofdata_to_platdata = mtk_eth_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .probe = mtk_eth_probe, + .remove = mtk_eth_remove, + .ops = &mtk_eth_ops, + .priv_auto_alloc_size = sizeof(struct mtk_eth_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/net/mtk_eth.h b/drivers/net/mtk_eth.h new file mode 100644 index 00000000000..fe89a03739f --- /dev/null +++ b/drivers/net/mtk_eth.h @@ -0,0 +1,286 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2018 MediaTek Inc. + * + * Author: Weijie Gao weijie.gao@mediatek.com + * Author: Mark Lee mark-mc.lee@mediatek.com + */ + +#ifndef _MTK_ETH_H_ +#define _MTK_ETH_H_ + +/* Frame Engine Register Bases */ +#define PDMA_BASE 0x0800 +#define GDMA1_BASE 0x0500 +#define GDMA2_BASE 0x1500 +#define GMAC_BASE 0x10000 + +/* Ethernet subsystem registers */ + +#define ETHSYS_SYSCFG0_REG 0x14 +#define SYSCFG0_GE_MODE_S(n) (12 + ((n) * 2)) +#define SYSCFG0_GE_MODE_M 0x3 + +#define ETHSYS_CLKCFG0_REG 0x2c +#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11) + +/* SYSCFG0_GE_MODE: GE Modes */ +#define GE_MODE_RGMII 0 +#define GE_MODE_MII 1 +#define GE_MODE_MII_PHY 2 +#define GE_MODE_RMII 3 + +/* Frame Engine Registers */ + +/* PDMA */ +#define TX_BASE_PTR_REG(n) (0x000 + (n) * 0x10) +#define TX_MAX_CNT_REG(n) (0x004 + (n) * 0x10) +#define TX_CTX_IDX_REG(n) (0x008 + (n) * 0x10) +#define TX_DTX_IDX_REG(n) (0x00c + (n) * 0x10) + +#define RX_BASE_PTR_REG(n) (0x100 + (n) * 0x10) +#define RX_MAX_CNT_REG(n) (0x104 + (n) * 0x10) +#define RX_CRX_IDX_REG(n) (0x108 + (n) * 0x10) +#define RX_DRX_IDX_REG(n) (0x10c + (n) * 0x10) + +#define PDMA_GLO_CFG_REG 0x204 +#define TX_WB_DDONE BIT(6) +#define RX_DMA_BUSY BIT(3) +#define RX_DMA_EN BIT(2) +#define TX_DMA_BUSY BIT(1) +#define TX_DMA_EN BIT(0) + +#define PDMA_RST_IDX_REG 0x208 +#define RST_DRX_IDX0 BIT(16) +#define RST_DTX_IDX0 BIT(0) + +/* GDMA */ +#define GDMA_IG_CTRL_REG 0x000 +#define GDM_ICS_EN BIT(22) +#define GDM_TCS_EN BIT(21) +#define GDM_UCS_EN BIT(20) +#define STRP_CRC BIT(16) +#define MYMAC_DP_S 12 +#define MYMAC_DP_M 0xf000 +#define BC_DP_S 8 +#define BC_DP_M 0xf00 +#define MC_DP_S 4 +#define MC_DP_M 0xf0 +#define UN_DP_S 0 +#define UN_DP_M 0x0f + +#define GDMA_MAC_LSB_REG 0x008 + +#define GDMA_MAC_MSB_REG 0x00c + +/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */ +#define DP_PDMA 0 +#define DP_GDMA1 1 +#define DP_GDMA2 2 +#define DP_PPE 4 +#define DP_QDMA 5 +#define DP_DISCARD 7 + +/* GMAC Registers */ + +#define GMAC_PIAC_REG 0x0004 +#define PHY_ACS_ST BIT(31) +#define MDIO_REG_ADDR_S 25 +#define MDIO_REG_ADDR_M 0x3e000000 +#define MDIO_PHY_ADDR_S 20 +#define MDIO_PHY_ADDR_M 0x1f00000 +#define MDIO_CMD_S 18 +#define MDIO_CMD_M 0xc0000 +#define MDIO_ST_S 16 +#define MDIO_ST_M 0x30000 +#define MDIO_RW_DATA_S 0 +#define MDIO_RW_DATA_M 0xffff + +/* MDIO_CMD: MDIO commands */ +#define MDIO_CMD_ADDR 0 +#define MDIO_CMD_WRITE 1 +#define MDIO_CMD_READ 2 +#define MDIO_CMD_READ_C45 3 + +/* MDIO_ST: MDIO start field */ +#define MDIO_ST_C45 0 +#define MDIO_ST_C22 1 + +#define GMAC_PORT_MCR(p) (0x0100 + (p) * 0x100) +#define MAC_RX_PKT_LEN_S 24 +#define MAC_RX_PKT_LEN_M 0x3000000 +#define IPG_CFG_S 18 +#define IPG_CFG_M 0xc0000 +#define MAC_MODE BIT(16) +#define FORCE_MODE BIT(15) +#define MAC_TX_EN BIT(14) +#define MAC_RX_EN BIT(13) +#define BKOFF_EN BIT(9) +#define BACKPR_EN BIT(8) +#define FORCE_RX_FC BIT(5) +#define FORCE_TX_FC BIT(4) +#define FORCE_SPD_S 2 +#define FORCE_SPD_M 0x0c +#define FORCE_DPX BIT(1) +#define FORCE_LINK BIT(0) + +/* MAC_RX_PKT_LEN: Max RX packet length */ +#define MAC_RX_PKT_LEN_1518 0 +#define MAC_RX_PKT_LEN_1536 1 +#define MAC_RX_PKT_LEN_1552 2 +#define MAC_RX_PKT_LEN_JUMBO 3 + +/* FORCE_SPD: Forced link speed */ +#define SPEED_10M 0 +#define SPEED_100M 1 +#define SPEED_1000M 2 + +#define GMAC_TRGMII_RCK_CTRL 0x300 +#define RX_RST BIT(31) +#define RXC_DQSISEL BIT(30) + +#define GMAC_TRGMII_TD_ODT(n) (0x354 + (n) * 8) +#define TD_DM_DRVN_S 4 +#define TD_DM_DRVN_M 0xf0 +#define TD_DM_DRVP_S 0 +#define TD_DM_DRVP_M 0x0f + +/* MT7530 Registers */ + +#define PCR_REG(p) (0x2004 + (p) * 0x100) +#define PORT_MATRIX_S 16 +#define PORT_MATRIX_M 0xff0000 + +#define PVC_REG(p) (0x2010 + (p) * 0x100) +#define STAG_VPID_S 16 +#define STAG_VPID_M 0xffff0000 +#define VLAN_ATTR_S 6 +#define VLAN_ATTR_M 0xc0 + +/* VLAN_ATTR: VLAN attributes */ +#define VLAN_ATTR_USER 0 +#define VLAN_ATTR_STACK 1 +#define VLAN_ATTR_TRANSLATION 2 +#define VLAN_ATTR_TRANSPARENT 3 + +#define PCMR_REG(p) (0x3000 + (p) * 0x100) +/* XXX: all fields are defined under GMAC_PORT_MCR */ + +#define SYS_CTRL_REG 0x7000 +#define SW_PHY_RST BIT(2) +#define SW_SYS_RST BIT(1) +#define SW_REG_RST BIT(0) + +#define NUM_TRGMII_CTRL 5 + +#define HWTRAP_REG 0x7800 +#define MHWTRAP_REG 0x7804 +#define CHG_TRAP BIT(16) +#define LOOPDET_DIS BIT(14) +#define P5_INTF_SEL_S 13 +#define P5_INTF_SEL_M 0x2000 +#define SMI_ADDR_S 11 +#define SMI_ADDR_M 0x1800 +#define XTAL_FSEL_S 9 +#define XTAL_FSEL_M 0x600 +#define P6_INTF_DIS BIT(8) +#define P5_INTF_MODE_S 7 +#define P5_INTF_MODE_M 0x80 +#define P5_INTF_DIS BIT(6) +#define C_MDIO_BPS BIT(5) +#define CHIP_MODE_S 0 +#define CHIP_MODE_M 0x0f + +/* P5_INTF_SEL: Interface type of Port5 */ +#define P5_INTF_SEL_GPHY 0 +#define P5_INTF_SEL_GMAC5 1 + +/* P5_INTF_MODE: Interface mode of Port5 */ +#define P5_INTF_MODE_GMII_MII 0 +#define P5_INTF_MODE_RGMII 1 + +#define MT7530_P6ECR 0x7830 +#define P6_INTF_MODE_M 0x3 +#define P6_INTF_MODE_S 0 + +/* P6_INTF_MODE: Interface mode of Port6 */ +#define P6_INTF_MODE_RGMII 0 +#define P6_INTF_MODE_TRGMII 1 + +#define MT7530_TRGMII_RD(n) (0x7a10 + (n) * 8) +#define RD_TAP_S 0 +#define RD_TAP_M 0x7f + +#define MT7530_TRGMII_TD_ODT(n) (0x7a54 + (n) * 8) +/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */ + +/* MT7530 GPHY MDIO Indirect Access Registers */ + +#define MII_MMD_ACC_CTL_REG 0x0d +#define MMD_CMD_S 14 +#define MMD_CMD_M 0xc000 +#define MMD_DEVAD_S 0 +#define MMD_DEVAD_M 0x1f + +/* MMD_CMD: MMD commands */ +#define MMD_ADDR 0 +#define MMD_DATA 1 +#define MMD_DATA_RW_POST_INC 2 +#define MMD_DATA_W_POST_INC 3 + +#define MII_MMD_ADDR_DATA_REG 0x0e + +/* MT7530 GPHY MDIO MMD Registers */ + +#define CORE_PLL_GROUP2 0x401 +#define RG_SYSPLL_EN_NORMAL BIT(15) +#define RG_SYSPLL_VODEN BIT(14) +#define RG_SYSPLL_POSDIV_S 5 +#define RG_SYSPLL_POSDIV_M 0x60 + +#define CORE_PLL_GROUP4 0x403 +#define RG_SYSPLL_DDSFBK_EN BIT(12) +#define RG_SYSPLL_BIAS_EN BIT(11) +#define RG_SYSPLL_BIAS_LPF_EN BIT(10) + +#define CORE_PLL_GROUP5 0x404 +#define RG_LCDDS_PCW_NCPO1_S 0 +#define RG_LCDDS_PCW_NCPO1_M 0xffff + +#define CORE_PLL_GROUP6 0x405 +#define RG_LCDDS_PCW_NCPO0_S 0 +#define RG_LCDDS_PCW_NCPO0_M 0xffff + +#define CORE_PLL_GROUP7 0x406 +#define RG_LCDDS_PWDB BIT(15) +#define RG_LCDDS_ISO_EN BIT(13) +#define RG_LCCDS_C_S 4 +#define RG_LCCDS_C_M 0x70 +#define RG_LCDDS_PCW_NCPO_CHG BIT(3) + +#define CORE_PLL_GROUP10 0x409 +#define RG_LCDDS_SSC_DELTA_S 0 +#define RG_LCDDS_SSC_DELTA_M 0xfff + +#define CORE_PLL_GROUP11 0x40a +#define RG_LCDDS_SSC_DELTA1_S 0 +#define RG_LCDDS_SSC_DELTA1_M 0xfff + +#define CORE_GSWPLL_GRP1 0x40d +#define RG_GSWPLL_POSDIV_200M_S 12 +#define RG_GSWPLL_POSDIV_200M_M 0x3000 +#define RG_GSWPLL_EN_PRE BIT(11) +#define RG_GSWPLL_FBKDIV_200M_S 0 +#define RG_GSWPLL_FBKDIV_200M_M 0xff + +#define CORE_GSWPLL_GRP2 0x40e +#define RG_GSWPLL_POSDIV_500M_S 8 +#define RG_GSWPLL_POSDIV_500M_M 0x300 +#define RG_GSWPLL_FBKDIV_500M_S 0 +#define RG_GSWPLL_FBKDIV_500M_M 0xff + +#define CORE_TRGMII_GSW_CLK_CG 0x410 +#define REG_GSWCK_EN BIT(0) +#define REG_TRGMIICK_EN BIT(1) + +#endif /* _MTK_ETH_H_ */

Hi,
nice to see ethernet-driver for bananapi r2 :)
but i have a problem while building:
drivers/net/mtk_eth.c: In function ‘mtk_eth_probe’: drivers/net/mtk_eth.c:1014:3: warning: implicit declaration of function ‘noncached_alloc’; did you mean ‘kmem_cache_alloc’? [-Wimplicit-function-declaration] noncached_alloc(sizeof(struct pdma_txdesc) * NUM_TX_DESC, ^~~~~~~~~~~~~~~ kmem_cache_alloc
searched for it:
./arch/arm/include/asm/system.h:571:phys_addr_t noncached_alloc(size_t size, size_t align);
and tried to fix by adding
#include <asm/system.h>
to drivers/net/mtk_eth.c, but still present. currently working on 2018-11, but 2019-01-rc2 seems to have no related change.
uploaded my staging here:
https://github.com/frank-w/u-boot/tree/bpi-r2_eth
any idea what i'm missing?
regards Frank
Gesendet: Donnerstag, 20. Dezember 2018 um 09:12 Uhr Von: "Weijie Gao" weijie.gao@mediatek.com diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c new file mode 100644 index 00000000000..cc09404830a --- /dev/null +++ b/drivers/net/mtk_eth.c
...
- /* Prepare for tx/rx rings */
- priv->tx_ring_noc = (struct pdma_txdesc *)
noncached_alloc(sizeof(struct pdma_txdesc) * NUM_TX_DESC,
ARCH_DMA_MINALIGN);
- priv->rx_ring_noc = (struct pdma_rxdesc *)
noncached_alloc(sizeof(struct pdma_rxdesc) * NUM_RX_DESC,
ARCH_DMA_MINALIGN);

with 2019-rc it comiles fine and loads kernel over tftp (wan-port).
U-Boot 2019.01-rc2-00012-g645c7a0418 (Dec 20 2018 - 10:56:50 +0100)
CPU: MediaTek MT7623 E3 DRAM: 2 GiB MMC: mmc@11230000: 0, mmc@11240000: 1 In: serial Out: serial Err: serial Net: Warning: ethernet@1b100000 (eth0) using random MAC address - fe:6f:b4:ff:e0:48 eth0: ethernet@1b100000 U-Boot> setenv ipaddr 192.168.0.11 U-Boot> setenv netmask 255.255.255.0 U-Boot> setenv serverip 192.168.0.10 U-Boot> setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait ip=dhcp U-Boot> setenv bootfile uImage_4.19.0-rc1-hdmiv5 U-Boot> tftp 0x80200000 ${bootfile} Using ethernet@1b100000 device TFTP from server 192.168.0.10; our IP address is 192.168.0.11 Filename 'uImage_4.19.0-rc1-hdmiv5'. Load address: 0x80200000 Loading: ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################################# ################################################ 263.7 KiB/s done Bytes transferred = 6231491 (5f15c3 hex) U-Boot> bootm 0x80200000 ## Booting kernel from Legacy Image at 80200000 ... Image Name: Linux Kernel 4.19.0-rc1-hdmiv5 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 6231427 Bytes = 5.9 MiB Load Address: 80008000 Entry Point: 80008000 Verifying Checksum ... OK Loading Kernel Image ... OK
Starting kernel ...
so i need to look why it's not working on 2018-11...
regards Frank
Tested-By: "Frank Wunderlich" frank-w@public-files.de

found it
missed this line in mt7623.h (git am breaked there because of my own changes and i only added 2 lines)
#define CONFIG_SYS_NONCACHED_MEMORY SZ_1M
compile works now
regards Frank

On Thu, Dec 20, 2018 at 04:12:53PM +0800, Weijie Gao wrote:
This patch adds ethernet support for Mediatek ARM-based SoCs, including a minimum setup of the integrated switch.
Cc: Joe Hershberger joe.hershberger@ni.com Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com Signed-off-by: Weijie Gao weijie.gao@mediatek.com Tested-By: "Frank Wunderlich" frank-w@public-files.de
Applied to u-boot/master, thanks!

This patch adds ethernet gmac node for MT7623 with MT7530 gigabit switch.
Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com --- arch/arm/dts/mt7623.dtsi | 21 ++++++++++++++++++++- arch/arm/dts/mt7623n-bananapi-bpi-r2.dts | 13 +++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/arch/arm/dts/mt7623.dtsi b/arch/arm/dts/mt7623.dtsi index f50f4ef1b92..448d1d73810 100644 --- a/arch/arm/dts/mt7623.dtsi +++ b/arch/arm/dts/mt7623.dtsi @@ -10,6 +10,7 @@ #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/power/mt7623-power.h> +#include <dt-bindings/reset/mtk-reset.h> #include "skeleton.dtsi"
/ { @@ -248,8 +249,26 @@ };
ethsys: syscon@1b000000 { - compatible = "mediatek,mt7623-ethsys"; + compatible = "mediatek,mt7623-ethsys", "syscon"; reg = <0x1b000000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; + }; + + eth: ethernet@1b100000 { + compatible = "mediatek,mt7623-eth", "syscon"; + reg = <0x1b100000 0x20000>; + clocks = <&topckgen CLK_TOP_ETHIF_SEL>, + <ðsys CLK_ETHSYS_ESW>, + <ðsys CLK_ETHSYS_GP1>, + <ðsys CLK_ETHSYS_GP2>, + <&apmixedsys CLK_APMIXED_TRGPLL>; + clock-names = "ethif", "esw", "gp1", "gp2", "trgpll"; + power-domains = <&scpsys MT7623_POWER_DOMAIN_ETH>; + resets = <ðsys ETHSYS_FE_RST>, + <ðsys ETHSYS_MCM_RST>; + reset-names = "fe", "mcm"; + mediatek,ethsys = <ðsys>; + status = "disabled"; }; }; diff --git a/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts b/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts index 84a77fde443..51628bb6399 100644 --- a/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts +++ b/arch/arm/dts/mt7623n-bananapi-bpi-r2.dts @@ -67,6 +67,19 @@ }; };
+ð { + status = "okay"; + mediatek,gmac-id = <0>; + phy-mode = "rgmii"; + mediatek,switch = "mt7530"; + reset-gpios = <&gpio 33 GPIO_ACTIVE_HIGH>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + &mmc0 { pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins_default>;

On Thu, Dec 20, 2018 at 04:12:54PM +0800, Weijie Gao wrote:
This patch adds ethernet gmac node for MT7623 with MT7530 gigabit switch.
Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com
Applied to u-boot/master, thanks!

This patch adds ethernet gmac node for MT7629 with internal gigabit phy.
Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com --- arch/arm/dts/mt7629-rfb.dts | 11 ++++++++++ arch/arm/dts/mt7629.dtsi | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+)
diff --git a/arch/arm/dts/mt7629-rfb.dts b/arch/arm/dts/mt7629-rfb.dts index a6d28a060f3..95d10aa6d32 100644 --- a/arch/arm/dts/mt7629-rfb.dts +++ b/arch/arm/dts/mt7629-rfb.dts @@ -22,6 +22,17 @@ }; };
+ð { + status = "okay"; + mediatek,gmac-id = <1>; + phy-mode = "gmii"; + phy-handle = <&phy0>; + + phy0: ethernet-phy@0 { + reg = <0>; + }; +}; + &pinctrl { qspi_pins: qspi-pins { mux { diff --git a/arch/arm/dts/mt7629.dtsi b/arch/arm/dts/mt7629.dtsi index e6052bbdcf3..c87115e0fe4 100644 --- a/arch/arm/dts/mt7629.dtsi +++ b/arch/arm/dts/mt7629.dtsi @@ -10,6 +10,7 @@ #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/power/mt7629-power.h> +#include <dt-bindings/reset/mtk-reset.h> #include "skeleton.dtsi"
/ { @@ -228,6 +229,48 @@ compatible = "mediatek,mt7629-ethsys", "syscon"; reg = <0x1b000000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; + }; + + eth: ethernet@1b100000 { + compatible = "mediatek,mt7629-eth", "syscon"; + reg = <0x1b100000 0x20000>; + clocks = <&topckgen CLK_TOP_ETH_SEL>, + <&topckgen CLK_TOP_F10M_REF_SEL>, + <ðsys CLK_ETH_ESW_EN>, + <ðsys CLK_ETH_GP0_EN>, + <ðsys CLK_ETH_GP1_EN>, + <ðsys CLK_ETH_GP2_EN>, + <ðsys CLK_ETH_FE_EN>, + <&sgmiisys0 CLK_SGMII_TX_EN>, + <&sgmiisys0 CLK_SGMII_RX_EN>, + <&sgmiisys0 CLK_SGMII_CDR_REF>, + <&sgmiisys0 CLK_SGMII_CDR_FB>, + <&sgmiisys1 CLK_SGMII_TX_EN>, + <&sgmiisys1 CLK_SGMII_RX_EN>, + <&sgmiisys1 CLK_SGMII_CDR_REF>, + <&sgmiisys1 CLK_SGMII_CDR_FB>, + <&apmixedsys CLK_APMIXED_SGMIPLL>, + <&apmixedsys CLK_APMIXED_ETH2PLL>; + clock-names = "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", + "fe", "sgmii_tx250m", "sgmii_rx250m", + "sgmii_cdr_ref", "sgmii_cdr_fb", + "sgmii2_tx250m", "sgmii2_rx250m", + "sgmii2_cdr_ref", "sgmii2_cdr_fb", + "sgmii_ck", "eth2pll"; + assigned-clocks = <&topckgen CLK_TOP_ETH_SEL>, + <&topckgen CLK_TOP_F10M_REF_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL1_D2>, + <&topckgen CLK_TOP_SGMIIPLL_D2>; + power-domains = <&scpsys MT7629_POWER_DOMAIN_ETHSYS>; + resets = <ðsys ETHSYS_FE_RST>; + reset-names = "fe"; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys0>; + mediatek,infracfg = <&infracfg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; };
sgmiisys0: syscon@1b128000 {

On Thu, Dec 20, 2018 at 04:12:55PM +0800, Weijie Gao wrote:
This patch adds ethernet gmac node for MT7629 with internal gigabit phy.
Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com
Applied to u-boot/master, thanks!

Enable ethernet related configs to mt7623n_bpir2_defconfig. Add default IP addresses. Enable noncached memory region required by ethernet driver.
Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com --- configs/mt7623n_bpir2_defconfig | 6 ++++++ include/configs/mt7623.h | 5 +++++ 2 files changed, 11 insertions(+)
diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig index 3a4de72e233..792a78d80c0 100644 --- a/configs/mt7623n_bpir2_defconfig +++ b/configs/mt7623n_bpir2_defconfig @@ -29,6 +29,7 @@ CONFIG_CMD_FAT=y CONFIG_CMD_FS_GENERIC=y CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="mt7623n-bananapi-bpi-r2" +CONFIG_NET_RANDOM_ETHADDR=y CONFIG_REGMAP=y CONFIG_SYSCON=y # CONFIG_BLOCK_CACHE is not set @@ -38,6 +39,11 @@ CONFIG_DM_MMC=y # CONFIG_MMC_QUIRKS is not set CONFIG_MMC_HS400_SUPPORT=y CONFIG_MMC_MTK=y +CONFIG_DM_RESET=y +CONFIG_RESET_MEDIATEK=y +CONFIG_PHY_FIXED=y +CONFIG_DM_ETH=y +CONFIG_MEDIATEK_ETH=y CONFIG_PINCTRL=y CONFIG_PINCONF=y CONFIG_PINCTRL_MT7623=y diff --git a/include/configs/mt7623.h b/include/configs/mt7623.h index ba763501cf2..5129c83da8f 100644 --- a/include/configs/mt7623.h +++ b/include/configs/mt7623.h @@ -24,6 +24,7 @@
/* Size of malloc() pool */ #define CONFIG_SYS_MALLOC_LEN SZ_4M +#define CONFIG_SYS_NONCACHED_MEMORY SZ_1M
/* Environment */ #define CONFIG_ENV_SIZE SZ_4K @@ -53,4 +54,8 @@ #define CONFIG_EXTRA_ENV_SETTINGS \ FDT_HIGH
+/* Ethernet */ +#define CONFIG_IPADDR 192.168.1.1 +#define CONFIG_SERVERIP 192.168.1.2 + #endif

On Thu, Dec 20, 2018 at 04:12:56PM +0800, Weijie Gao wrote:
Enable ethernet related configs to mt7623n_bpir2_defconfig. Add default IP addresses. Enable noncached memory region required by ethernet driver.
Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com
Applied to u-boot/master, thanks!

Enable ethernet related configs to mt7629_rfb_defconfig. Add default IP addresses. Enable noncached memory region required by ethernet driver.
Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com --- configs/mt7629_rfb_defconfig | 5 +++++ include/configs/mt7629.h | 5 +++++ 2 files changed, 10 insertions(+)
diff --git a/configs/mt7629_rfb_defconfig b/configs/mt7629_rfb_defconfig index 1729d13c3d3..fdd5f575774 100644 --- a/configs/mt7629_rfb_defconfig +++ b/configs/mt7629_rfb_defconfig @@ -32,6 +32,7 @@ CONFIG_CMD_PING=y CONFIG_OF_EMBED=y CONFIG_DEFAULT_DEVICE_TREE="mt7629-rfb" CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-parents" +CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_DM_SEQ_ALIAS=y CONFIG_REGMAP=y CONFIG_SPL_REGMAP=y @@ -51,6 +52,10 @@ CONFIG_SPI_FLASH_MACRONIX=y CONFIG_SPI_FLASH_SPANSION=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_WINBOND=y +CONFIG_DM_RESET=y +CONFIG_RESET_MEDIATEK=y +CONFIG_DM_ETH=y +CONFIG_MEDIATEK_ETH=y CONFIG_PINCTRL=y CONFIG_PINCONF=y CONFIG_PINCTRL_MT7629=y diff --git a/include/configs/mt7629.h b/include/configs/mt7629.h index a665a5eb7f2..9910d8c89a6 100644 --- a/include/configs/mt7629.h +++ b/include/configs/mt7629.h @@ -24,6 +24,7 @@
/* Size of malloc() pool */ #define CONFIG_SYS_MALLOC_LEN SZ_4M +#define CONFIG_SYS_NONCACHED_MEMORY SZ_1M
/* Environment */ #define CONFIG_ENV_SIZE SZ_4K @@ -54,4 +55,8 @@ /* DRAM */ #define CONFIG_SYS_SDRAM_BASE 0x40000000
+/* Ethernet */ +#define CONFIG_IPADDR 192.168.1.1 +#define CONFIG_SERVERIP 192.168.1.2 + #endif

On Thu, Dec 20, 2018 at 04:12:57PM +0800, Weijie Gao wrote:
Enable ethernet related configs to mt7629_rfb_defconfig. Add default IP addresses. Enable noncached memory region required by ethernet driver.
Signed-off-by: Mark Lee Mark-MC.Lee@mediatek.com
Applied to u-boot/master, thanks!

This patch adds new file entries for MediaTek SoCs
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS index 0cec39c542d..54218ee5e9d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -176,6 +176,8 @@ F: drivers/ram/mediatek/ F: drivers/spi/mtk_qspi.c F: drivers/timer/mtk_timer.c F: drivers/watchdog/mtk_wdt.c +F: drivers/net/mtk_eth.c +F: drivers/reset/reset-mediatek.c F: tools/mtk_image.c F: tools/mtk_image.h N: mediatek

On Thu, Dec 20, 2018 at 04:12:58PM +0800, Weijie Gao wrote:
This patch adds new file entries for MediaTek SoCs
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
Applied to u-boot/master, thanks!

This patch replace OF_EMBED with OF_SEPARATE of defconfig files of MediaTek boards because now OF_EMBED is only used for debugging purpose.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com --- configs/mt7623n_bpir2_defconfig | 2 +- configs/mt7629_rfb_defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig index 792a78d80c0..1a973672627 100644 --- a/configs/mt7623n_bpir2_defconfig +++ b/configs/mt7623n_bpir2_defconfig @@ -27,7 +27,7 @@ CONFIG_CMD_READ=y CONFIG_CMD_PING=y CONFIG_CMD_FAT=y CONFIG_CMD_FS_GENERIC=y -CONFIG_OF_EMBED=y +CONFIG_OF_SEPARATE=y CONFIG_DEFAULT_DEVICE_TREE="mt7623n-bananapi-bpi-r2" CONFIG_NET_RANDOM_ETHADDR=y CONFIG_REGMAP=y diff --git a/configs/mt7629_rfb_defconfig b/configs/mt7629_rfb_defconfig index fdd5f575774..1da9932dcd9 100644 --- a/configs/mt7629_rfb_defconfig +++ b/configs/mt7629_rfb_defconfig @@ -29,7 +29,7 @@ CONFIG_CMD_SF_TEST=y # CONFIG_CMD_NFS is not set CONFIG_CMD_PING=y # CONFIG_PARTITIONS is not set -CONFIG_OF_EMBED=y +CONFIG_OF_SEPARATE=y CONFIG_DEFAULT_DEVICE_TREE="mt7629-rfb" CONFIG_OF_SPL_REMOVE_PROPS="pinctrl-0 pinctrl-names clock-names interrupt-parent assigned-clocks assigned-clock-parents" CONFIG_NET_RANDOM_ETHADDR=y

On Thu, 20 Dec 2018 at 01:13, Weijie Gao weijie.gao@mediatek.com wrote:
This patch replace OF_EMBED with OF_SEPARATE of defconfig files of MediaTek boards because now OF_EMBED is only used for debugging purpose.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com
configs/mt7623n_bpir2_defconfig | 2 +- configs/mt7629_rfb_defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

On Thu, Dec 20, 2018 at 04:12:59PM +0800, Weijie Gao wrote:
This patch replace OF_EMBED with OF_SEPARATE of defconfig files of MediaTek boards because now OF_EMBED is only used for debugging purpose.
Signed-off-by: Weijie Gao weijie.gao@mediatek.com Reviewed-by: Simon Glass sjg@chromium.org
Applied to u-boot/master, thanks!
participants (4)
-
Frank Wunderlich
-
Simon Glass
-
Tom Rini
-
Weijie Gao