net: Add MT76xx ethernet driver
Subsystems (4)
PATCH 1/1 net: Add MT76xx ethernet driver
This patch adds ethernet support for the Mediatek MT76xx SoC, including a minimum setup of the integrated switch. This driver is loosly based on the driver version included in this MediaTek github repository:
https://github.com/MediaTek-Labs/linkit-smart-uboot.git
Tested on the MT7688 LinkIt smart-gateway and on the Gardena-smart-gateway.
--- drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/mt76xx-eth.c | 648 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 656 insertions(+) create mode 100644 drivers/net/mt76xx-eth.c
drivers/net/Kconfig +7 -0
@@ -227,6 +227,13 @@ config MACB_ZYNQ The Cadence MACB ethernet interface was used on Zynq platform. Say Y to enable support for the MACB/GEM in Zynq chip. +config MT76XX_ETH + bool "MediaTek MT76xx Ethernet Interface" + depends on ARCH_MT7620 + help + The MediaTek MT76xx ethernet interface is used on MT7688 + based boards. + config PCH_GBE bool "Intel Platform Controller Hub EG20T GMAC driver" depends on DM_ETH && DM_PCI
drivers/net/Makefile +1 -0
@@ -37,6 +37,7 @@ obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o +obj-$(CONFIG_MT76XX_ETH) += mt76xx-eth.o obj-$(CONFIG_MVGBE) += mvgbe.o obj-$(CONFIG_MVNETA) += mvneta.o obj-$(CONFIG_MVPP2) += mvpp2.o
drivers/net/mt76xx-eth.c new file +648 -0
648 lines not on this page · raw message
Signature · 1 line
2.19.0
PATCH 1/1 gpio: Add MT7621 GPIO support
This patch adds GPIO support for the Mediatek MT7621 SoC, tested on MT7688 (Gardena smart-gateway). The driver is loosly based on the Linux kernel version.
--- drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + drivers/gpio/mt7621_gpio.c | 212 +++++++++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 drivers/gpio/mt7621_gpio.c
drivers/gpio/Kconfig +8 -0
@@ -314,4 +314,12 @@ config MPC8XXX_GPIO Aside from the standard functions of input/output mode, and output value setting, the open-drain feature, which can configure individual GPIOs to work as open-drain outputs, is supported. + +config MT7621_GPIO + bool "MediaTek MT7621 GPIO driver" + depends on DM_GPIO && ARCH_MT7620 + default y + help + Say yes here to support MediaTek MT7621 compatible GPIOs. + endmenu
drivers/gpio/Makefile +1 -0
@@ -58,3 +58,4 @@ obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o obj-$(CONFIG_MSM_GPIO) += msm_gpio.o obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o +obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
drivers/gpio/mt7621_gpio.c new file +212 -0
212 lines not on this page · raw message
Signature · 1 line
2.19.0
PATCH 1/1 gpio: Add MT7621 GPIO support
Quoted 116 lines · Stefan Roese
This patch adds GPIO support for the Mediatek MT7621 SoC, tested on MT7688 (Gardena smart-gateway). The driver is loosly based on the Linux kernel version.
Signed-off-by Stefan Roese <[email protected]>Cc Daniel Schwierzeck <[email protected]>--- drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + drivers/gpio/mt7621_gpio.c | 212 +++++++++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 drivers/gpio/mt7621_gpio.cdrivers/gpio/Kconfig +8
-0@@ -314,4 +314,12 @@ config MPC8XXX_GPIO Aside from the standard functions of input/output mode, and output value setting, the open-drain feature, which can configure individual GPIOs to work as open-drain outputs, is supported. + +config MT7621_GPIO + bool "MediaTek MT7621 GPIO driver" + depends on DM_GPIO && ARCH_MT7620 + default y + help + Say yes here to support MediaTek MT7621 compatible GPIOs. + endmenudrivers/gpio/Makefile +1
-0@@ -58,3 +58,4 @@ obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o obj-$(CONFIG_MSM_GPIO) += msm_gpio.o obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o +obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.odrivers/gpio/mt7621_gpio.c new file +71
-0@@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* Copyright (C) 2018 Stefan Roese <[email protected]> +* +* Based on the Linux driver version which is: +* Copyright (C) 2009-2011 Gabor Juhos <[email protected]> +* Copyright (C) 2013 John Crispin <[email protected]> +*/ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <linux/io.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <dm/device-internal.h> +#include <dt-bindings/gpio/gpio.h> + +#define MTK_MAX_BANK 3 +#define MTK_BANK_WIDTH 32 + +enum mediatek_gpio_reg { +GPIO_REG_CTRL =0 , +GPIO_REG_POL , +GPIO_REG_DATA , +GPIO_REG_DSET , +GPIO_REG_DCLR , +GPIO_REG_REDGE , +GPIO_REG_FEDGE , +GPIO_REG_HLVL , +GPIO_REG_LLVL , +GPIO_REG_STAT , +GPIO_REG_EDGE , +}; + +static void __iomem *mediatek_gpio_membase; + +struct mediatek_gpio_platdata { +const char *bank_name;/* Name of bank, e.g. "B" */ +int gpio_count; +int bank; +}; + +static void mtk_gpio_w32 (int bank,u8 reg,u32 val) +{ +iowrite32 (val, mediatek_gpio_membase + (reg *0x10 ) + (bank *0x4 )); +} + +static u32 mtk_gpio_r32 (int bank,u8 reg) +{ +return ioread32 (mediatek_gpio_membase + (reg *0x10 ) + (bank *0x4 )); +} + +static int mediatek_gpio_get_value (struct udevice *dev,unsigned offset) +{ +struct mediatek_gpio_platdata *plat =dev_get_platdata (dev); + +return !!(mtk_gpio_r32 (plat->bank,GPIO_REG_DATA ) &BIT (offset)); +} + +static int mediatek_gpio_set_value (struct udevice *dev,unsigned offset, +int value) +{ +struct mediatek_gpio_platdata *plat =dev_get_platdata (dev); + +mtk_gpio_w32 (plat->bank, (value) ?GPIO_REG_DSET : +GPIO_REG_DCLR ,BIT (offset)); + +return 0 ;
drivers/gpio/mt7621_gpio.c line 81
Quoted 10 lines
drivers/gpio/mt7621_gpio.c new file +10
-0+} + +static int mediatek_gpio_direction_input (struct udevice *dev,unsigned offset) +{ +struct mediatek_gpio_platdata *plat =dev_get_platdata (dev); +u32 t; + + t =mtk_gpio_r32 (plat->bank,GPIO_REG_CTRL ); + t &= ~BIT (offset); +mtk_gpio_w32 (plat->bank,GPIO_REG_CTRL , t);
I would only wrap the "(reg * 0x10) + (bank * 0x4)" into a function and directly use the I/O functions. Then you could also use clrbits, setbits etc.
Quoted 46 lines
drivers/gpio/mt7621_gpio.c new file +46
-0+ +return 0 ; +} + +static int mediatek_gpio_direction_output (struct udevice *dev,unsigned offset, +int value) +{ +struct mediatek_gpio_platdata *plat =dev_get_platdata (dev); +u32 t; + + t =mtk_gpio_r32 (plat->bank,GPIO_REG_CTRL ); + t |=BIT (offset); +mtk_gpio_w32 (plat->bank,GPIO_REG_CTRL , t); +mediatek_gpio_set_value (dev, offset, value); + +return 0 ; +} + +static int mediatek_gpio_get_function (struct udevice *dev,unsigned offset) +{ +struct mediatek_gpio_platdata *plat =dev_get_platdata (dev); +u32 t; + + t =mtk_gpio_r32 (plat->bank,GPIO_REG_CTRL ); +if (t &BIT (offset)) +return GPIOF_OUTPUT ; + +return GPIOF_INPUT ; +} + +static const struct dm_gpio_ops gpio_mediatek_ops = { + .direction_input = mediatek_gpio_direction_input, + .direction_output = mediatek_gpio_direction_output, + .get_value = mediatek_gpio_get_value, + .set_value = mediatek_gpio_set_value, + .get_function = mediatek_gpio_get_function, +}; + +/** +* Returns the name of a GPIO bank +* +* GPIO banks are named A, B, C, ... +* +* @bank: Bank number (0, 1..n-1) +* @return allocated string containing the name +*/
drivers/gpio/mt7621_gpio.c line 137
Quoted 10 lines
drivers/gpio/mt7621_gpio.c new file +10
-0+static char *gpio_bank_name (int bank) +{ +char *name; + + name =malloc (3 ); +if (name) { + name[0 ] ='P' ; + name[1 ] ='A' + bank; + name[2 ] ='\0' ; + }
you could save this malloc() if you simply use "char bank_name[3]" in plat_data and pass it to this function
Quoted 30 lines
drivers/gpio/mt7621_gpio.c new file +30
-0+ +return name; +} + +static int gpio_mediatek_probe (struct udevice *dev) +{ +struct mediatek_gpio_platdata *plat =dev_get_platdata (dev); +struct gpio_dev_priv *uc_priv =dev_get_uclass_priv (dev); + +/* Tell the uclass how many GPIOs we have */ +if (plat) { + uc_priv->gpio_count = plat->gpio_count; + uc_priv->bank_name = plat->bank_name; + } + +return 0 ; +} + +/** +* We have a top-level GPIO device with no actual GPIOs. It has a child +* device for each Mediatek bank. +*/ +static int gpio_mediatek_bind (struct udevice *parent) +{ +struct mediatek_gpio_platdata *plat = parent->platdata; +const void *blob = gd->fdt_blob; +int node =dev_of_offset (parent); +int bank =0 ; +int subnode; +int ret;
drivers/gpio/mt7621_gpio.c line 177
Quoted 10 lines
drivers/gpio/mt7621_gpio.c new file +10
-0+ +/* If this is a child device, there is nothing to do here */ +if (plat) +return 0 ; + + mediatek_gpio_membase =dev_remap_addr (parent); +if (!mediatek_gpio_membase) +return -EINVAL ; + +fdt_for_each_subnode (subnode, blob, node) {
I think this loop can be rewritten with dev_read_first_subnode() and dev_read_next_subnode() to be compatible with DM live tree
Quoted 36 lines
drivers/gpio/mt7621_gpio.c new file +35
-0+struct mediatek_gpio_platdata *plat; +struct udevice *dev; + + plat =calloc (1 ,sizeof (*plat)); +if (!plat) +return -ENOMEM ; + plat->bank_name =gpio_bank_name (bank); + plat->gpio_count =MTK_BANK_WIDTH ; + plat->bank = bank; + + ret =device_bind (parent, parent->driver, + plat->bank_name, plat,-1 , &dev); +if (ret) +return ret; + +dev_set_of_offset (dev, subnode); + bank++; + } + +return 0 ; +} + +static const struct udevice_id mediatek_gpio_ids[] = { + { .compatible ="mtk,mt7621-gpio" }, + { } +}; + +U_BOOT_DRIVER (gpio_mediatek) = { + .name ="gpio_mediatek" , + .id =UCLASS_GPIO , + .ops = &gpio_mediatek_ops, + .of_match = mediatek_gpio_ids, + .bind = gpio_mediatek_bind, + .probe = gpio_mediatek_probe, +};
Signature · 9 lines
- Daniel -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: OpenPGP digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20181007/273fd550/attachment.sig>
PATCH 1/1 gpio: Add MT7621 GPIO support
Quoted 125 lines · Daniel Schwierzeck
Quoted 122 lines · Stefan Roese
This patch adds GPIO support for the Mediatek MT7621 SoC, tested on MT7688 (Gardena smart-gateway). The driver is loosly based on the Linux kernel version.
Signed-off-by Stefan Roese <[email protected]>Cc Daniel Schwierzeck <[email protected]>--- drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + drivers/gpio/mt7621_gpio.c | 212 +++++++++++++++++++++++++++++++++++++ 3 files changed, 221 insertions(+)create mode 100644
drivers/gpio/mt7621_gpio.cdrivers/gpio/Kconfig +8
-0@@ -314,4 +314,12 @@ config MPC8XXX_GPIO Aside from the standard functions of input/output mode, and output value setting, the open-drain feature, which can configure individual GPIOs to work as open-drain outputs, is supported. + +config MT7621_GPIO + bool "MediaTek MT7621 GPIO driver" + depends on DM_GPIO && ARCH_MT7620 + default y + help + Say yes here to support MediaTek MT7621 compatible GPIOs. + endmenudrivers/gpio/Makefile +1
-0@@ -58,3 +58,4 @@ obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o obj-$(CONFIG_MSM_GPIO) += msm_gpio.o obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o obj-$(CONFIG_PM8916_GPIO) += pm8916_gpio.o +obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.odrivers/gpio/mt7621_gpio.c new file +77
-0@@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* Copyright (C) 2018 Stefan Roese <[email protected]> +* +* Based on the Linux driver version which is: +* Copyright (C) 2009-2011 Gabor Juhos <[email protected]> +* Copyright (C) 2013 John Crispin <[email protected]> +*/ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> +#include <linux/io.h> +#include <asm/io.h> +#include <asm/gpio.h> +#include <dm/device-internal.h> +#include <dt-bindings/gpio/gpio.h> + +#define MTK_MAX_BANK 3 +#define MTK_BANK_WIDTH 32 + +enum mediatek_gpio_reg { +GPIO_REG_CTRL =0 , +GPIO_REG_POL , +GPIO_REG_DATA , +GPIO_REG_DSET , +GPIO_REG_DCLR , +GPIO_REG_REDGE , +GPIO_REG_FEDGE , +GPIO_REG_HLVL , +GPIO_REG_LLVL , +GPIO_REG_STAT , +GPIO_REG_EDGE , +}; + +static void __iomem *mediatek_gpio_membase; + +struct mediatek_gpio_platdata { +const char *bank_name;/* Name of bank, e.g. "B" */ +int gpio_count; +int bank; +}; + +static void mtk_gpio_w32 (int bank,u8 reg,u32 val) +{ +iowrite32 (val, mediatek_gpio_membase + (reg *0x10 ) + (bank *0x4 )); +} + +static u32 mtk_gpio_r32 (int bank,u8 reg) +{ +return ioread32 (mediatek_gpio_membase + (reg *0x10 ) + (bank *0x4 )); +} + +static int mediatek_gpio_get_value (struct udevice *dev,unsigned offset) +{ +struct mediatek_gpio_platdata *plat =dev_get_platdata (dev); + +return !!(mtk_gpio_r32 (plat->bank,GPIO_REG_DATA ) &BIT (offset)); +} + +static int mediatek_gpio_set_value (struct udevice *dev,unsigned offset, +int value) +{ +struct mediatek_gpio_platdata *plat =dev_get_platdata (dev); + +mtk_gpio_w32 (plat->bank, (value) ?GPIO_REG_DSET : +GPIO_REG_DCLR ,BIT (offset)); + +return 0 ; +} + +static int mediatek_gpio_direction_input (struct udevice *dev,unsigned offset) +{ +struct mediatek_gpio_platdata *plat =dev_get_platdata (dev); +u32 t;
Quoted 8 lines
drivers/gpio/mt7621_gpio.c line 81
Quoted 4 lines
drivers/gpio/mt7621_gpio.c new file +4
-0+ + t =mtk_gpio_r32 (plat->bank,GPIO_REG_CTRL ); + t &= ~BIT (offset); +mtk_gpio_w32 (plat->bank,GPIO_REG_CTRL , t);I would only wrap the "(reg *
0x10) + (bank *0x4)" into a function and directly use the I/O functions. Then you could also use clrbits, setbits etc.
As you might have guessed, the current implementation with its IO wrappers is copied from the Linux source. But I agree, that it makes sense to drop those wrappers. Will do in v2 - including the other review comments.
Thanks,
Stefan
PATCH 1/1 wdt: Add MT7621 watchdog driver
In reply to Stefan RoeseThis patch adds watchdog support for the Mediatek MT7621 SoC. The driver is loosly based on the Linux kernel version.
--- drivers/watchdog/Kconfig | 7 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/mt7621_wdt.c | 102 ++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 drivers/watchdog/mt7621_wdt.c
drivers/watchdog/Kconfig +7 -0
@@ -111,4 +111,11 @@ config XILINX_TB_WATCHDOG Select this to enable Xilinx Axi watchdog timer, which can be found on some Xilinx Microblaze Platforms. +config WDT_MT7621 + bool "MediaTek MT7621 watchdog timer support" + depends on WDT && ARCH_MT7620 + help + Select this to enable Ralink / Mediatek watchdog timer, + which can be found on some MediaTek chips. + endmenu
drivers/watchdog/Makefile +1 -0
@@ -23,3 +23,4 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o +obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o
drivers/watchdog/mt7621_wdt.c new file +102 -0
102 lines not on this page · raw message
Signature · 1 line
2.19.0
PATCH 1/1 wdt: Add MT7621 watchdog driver
Quoted 12 lines · Stefan Roese
This patch adds watchdog support for the Mediatek MT7621 SoC. The driver is loosly based on the Linux kernel version.
Signed-off-by Stefan Roese <[email protected]>Cc Daniel Schwierzeck <[email protected]>--- drivers/watchdog/Kconfig | 7 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/mt7621_wdt.c | 102 ++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 drivers/watchdog/mt7621_wdt.c
Signature · 9 lines
- Daniel -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: OpenPGP digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20181007/2f817f40/attachment.sig>
PATCH 1/1 wdt: Add MT7621 watchdog driver
In reply to Stefan RoeseAm 04.10.18 um 13:39 schrieb Stefan Roese:
Quoted 12 lines
This patch adds watchdog support for the Mediatek MT7621 SoC. The driver is loosly based on the Linux kernel version.
Signed-off-by Stefan Roese <[email protected]>Cc Daniel Schwierzeck <[email protected]>--- drivers/watchdog/Kconfig | 7 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/mt7621_wdt.c | 102 ++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 drivers/watchdog/mt7621_wdt.c
applied to u-boot-mips/next, thanks.
Signature · 9 lines
- Daniel -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: OpenPGP digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20181028/e9d244ba/attachment.sig>
PATCH 1/1 common: Add arch_misc_init() prototype to include/init.h
In reply to Stefan RoeseWhen implementing arch_misc_init() for the MT7620 platform I noticed that this function prototype is missing. Lets add this prototype to the common place (init.h) so that we use this function on all architectures.
--- include/init.h | 1 + 1 file changed, 1 insertion(+)
include/init.h +1 -0
@@ -165,6 +165,7 @@ void arch_setup_gd(gd_t *gd_ptr);/* common/board_r.c */ void board_init_r (gd_t *id,ulong dest_addr) __attribute__ ((noreturn)); +int arch_misc_init (void );int cpu_init_r (void );int last_stage_init (void );int mac_read_from_eeprom (void );
Signature · 1 line
2.19.0
PATCH 1/1 common: Add arch_misc_init() prototype to include/init.h
Hi Stefan
Quoted 27 lines
From: Stefan Roese <[email protected]>
Sent: jeudi 4 octobre 2018 13:39When implementing
arch_misc_init()for the MT7620 platform I noticed that this function prototype is missing. Lets add this prototype to the common place (init.h) so that we use this function on all architectures.Signed-off-by Stefan Roese <[email protected]>Cc Daniel Schwierzeck <[email protected]>Cc Patrick Delaunay <[email protected]>Cc Tom Rini <[email protected]>--- include/init.h | 1 + 1 file changed, 1 insertion(+)include/init.h +1
-1@@ -165,6 +165,7 @@ void arch_setup_gd(gd_t *gd_ptr);/* common/board_r.c */ void board_init_r (gd_t *id,ulong dest_addr) __attribute__ ((noreturn)); +int arch_misc_init (void );int cpu_init_r (void );int last_stage_init (void );int mac_read_from_eeprom (void ); --
Quoted 1 line
2.19.0
I found prototype of the function for arm and x86 in
./arch/arm/include/asm/u-boot-arm.h:35:int arch_misc_init(void);
./arch/x86/include/asm/u-boot-x86.h:73:int arch_misc_init(void);
I think , theyr should be removed in this include if a generic prototype is defined in init.h
But it is the fact for other prototypes for "cpu.c", at least for
- arch_cpu_init
- arch_early_init_r
include path is :
./include/common.h:51:#include <asm/u-boot.h> ./arch/arm/include/asm/u-boot.h:24:#include <asm/u-boot-arm.h>
Regards
Patrick
PATCH 1/1 net: Add MT76xx ethernet driver
In reply to Stefan RoeseQuoted 219 lines · Stefan Roese
This patch adds ethernet support for the Mediatek MT76xx SoC, including a minimum setup of the integrated switch. This driver is loosly based on the driver version included in this MediaTek github repository:
https://github.com/MediaTek-Labs/linkit-smart-uboot.git
Tested on the MT7688 LinkIt smart-gateway and on the Gardena-smart-gateway.
Signed-off-by Stefan Roese <[email protected]>Cc Daniel Schwierzeck <[email protected]>Cc Joe Hershberger <[email protected]>--- drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/mt76xx-eth.c | 648 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 656 insertions(+) create mode 100644 drivers/net/mt76xx-eth.cdrivers/net/Kconfig +7
-0@@ -227,6 +227,13 @@ config MACB_ZYNQ The Cadence MACB ethernet interface was used on Zynq platform. Say Y to enable support for the MACB/GEM in Zynq chip. +config MT76XX_ETH + bool "MediaTek MT76xx Ethernet Interface" + depends on ARCH_MT7620 + help + The MediaTek MT76xx ethernet interface is used on MT7688 + based boards. + config PCH_GBE bool "Intel Platform Controller Hub EG20T GMAC driver" depends on DM_ETH && DM_PCIdrivers/net/Makefile +1
-0@@ -37,6 +37,7 @@ obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o +obj-$(CONFIG_MT76XX_ETH) += mt76xx-eth.o obj-$(CONFIG_MVGBE) += mvgbe.o obj-$(CONFIG_MVNETA) += mvneta.o obj-$(CONFIG_MVPP2) += mvpp2.odrivers/net/mt76xx-eth.c new file +164
-0@@ -0,0 +1,648 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* MediaTek ethernet IP driver for U-Boot +* +* Copyright (C) 2018 Stefan Roese <[email protected]> +* +* This code is mostly based on the code extracted from this MediaTek +* github repository: +* +* https://github.com/MediaTek-Labs/linkit-smart-uboot.git +* +* I was not able to find a specific license or other developers +* copyrights here, so I can't add them here. +*/ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <miiphy.h> +#include <net.h> +#include <wait_bit.h> +#include <asm/io.h> +#include <linux/err.h> + +/* System controller register */ +#define MT76XX_RSTCTRL_REG 0x34 +#define RSTCTRL_EPHY_RST BIT(24) + +#define MT76XX_AGPIO_CFG_REG 0x3c +#define MT7628_EPHY_GPIO_AIO_EN GENMASK(20, 17) +#define MT7628_EPHY_P0_DIS BIT(16) + +#define MT76XX_GPIO2_MODE_REG 0x64 + +/* Ethernet frame engine register */ +#define PDMA_RELATED 0x0800 + +#define TX_BASE_PTR0 (PDMA_RELATED + 0x000) +#define TX_MAX_CNT0 (PDMA_RELATED + 0x004) +#define TX_CTX_IDX0 (PDMA_RELATED + 0x008) +#define TX_DTX_IDX0 (PDMA_RELATED + 0x00c) + +#define RX_BASE_PTR0 (PDMA_RELATED + 0x100) +#define RX_MAX_CNT0 (PDMA_RELATED + 0x104) +#define RX_CALC_IDX0 (PDMA_RELATED + 0x108) + +#define PDMA_GLO_CFG (PDMA_RELATED + 0x204) +#define PDMA_RST_IDX (PDMA_RELATED + 0x208) +#define DLY_INT_CFG (PDMA_RELATED + 0x20c) + +#define SDM_RELATED 0x0c00 + +#define SDM_MAC_ADRL (SDM_RELATED + 0x0c)/* MAC address LSB */ +#define SDM_MAC_ADRH (SDM_RELATED + 0x10)/* MAC Address MSB */ + +#define RST_DTX_IDX0 BIT(0) +#define RST_DRX_IDX0 BIT(16) + +#define TX_DMA_EN BIT(0) +#define TX_DMA_BUSY BIT(1) +#define RX_DMA_EN BIT(2) +#define RX_DMA_BUSY BIT(3) +#define TX_WB_DDONE BIT(6) + +/* Ethernet switch register */ +#define MT76XX_SWITCH_FCT0 0x0008 +#define MT76XX_SWITCH_PFC1 0x0014 +#define MT76XX_SWITCH_FPA 0x0084 +#define MT76XX_SWITCH_SOCPC 0x008c +#define MT76XX_SWITCH_POC0 0x0090 +#define MT76XX_SWITCH_POC2 0x0098 +#define MT76XX_SWITCH_SGC 0x009c +#define MT76XX_SWITCH_PCR0 0x00c0 +#define MT76XX_SWITCH_PCR1 0x00c4 +#define MT76XX_SWITCH_FPA1 0x00c8 +#define MT76XX_SWITCH_FCT2 0x00cc +#define MT76XX_SWITCH_SGC2 0x00e4 +#define MT76XX_SWITCH_BMU_CTRL 0x0110 + +/* rxd2 */ +#define RX_DMA_DONE BIT(31) +#define RX_DMA_LSO BIT(30) +#define RX_DMA_PLEN0 (_x) (((_x) & 0x3fff) << 16) +#define RX_DMA_GET_PLEN0 (_x) (((_x) >> 16) & 0x3fff) +#define RX_DMA_TAG BIT(15) +/* rxd3 */ +#define RX_DMA_TPID (_x) (((_x) >> 16) & 0xffff) +#define RX_DMA_VID (_x) ((_x) & 0xffff) +/* rxd4 */ +#define RX_DMA_L4VALID BIT(30) + +struct fe_rx_dma { +unsigned int rxd1; +unsigned int rxd2; +unsigned int rxd3; +unsigned int rxd4; +} __packed__aligned(4) ; + +#define TX_DMA_BUF_LEN 0x3fff +#define TX_DMA_PLEN0_MASK (TX_DMA_BUF_LEN << 16) +#define TX_DMA_PLEN0 (_x) (((_x) & TX_DMA_BUF_LEN) << 16) +#define TX_DMA_PLEN1 (_x) ((_x) & TX_DMA_BUF_LEN) +#define TX_DMA_GET_PLEN0 (_x) (((_x) >> 16) & TX_DMA_BUF_LEN) +#define TX_DMA_GET_PLEN1 (_x) ((_x) & TX_DMA_BUF_LEN) +#define TX_DMA_LS1 BIT(14) +#define TX_DMA_LS0 BIT(30) +#define TX_DMA_DONE BIT(31) + +#define TX_DMA_INS_VLAN_MT7621 BIT(16) +#define TX_DMA_INS_VLAN BIT(7) +#define TX_DMA_INS_PPPOE BIT(12) +#define TX_DMA_QN (_x) ((_x) << 16) +#define TX_DMA_PN (_x) ((_x) << 24) +#define TX_DMA_QN_MASK TX_DMA_QN(0x7) +#define TX_DMA_PN_MASK TX_DMA_PN(0x7) +#define TX_DMA_UDF BIT(20) +#define TX_DMA_CHKSUM (0x7 << 29) +#define TX_DMA_TSO BIT(28) + +struct fe_tx_dma { +unsigned int txd1; +unsigned int txd2; +unsigned int txd3; +unsigned int txd4; +} __packed__aligned(4) ; + +#define NUM_RX_DESC 256 +#define NUM_TX_DESC 4 + +#define PADDING_LENGTH 60 + +#define MTK_QDMA_PAGE_SIZE 2048 + +#define CONFIG_MDIO_TIMEOUT 100 +#define CONFIG_DMA_STOP_TIMEOUT 100 +#define CONFIG_TX_DMA_TIMEOUT 100 + +#define LINK_DELAY_TIME 500/* 500 ms */ +#define LINK_TIMEOUT 10000/* 10 seconds */ + +struct mt76xx_eth_dev { +void __iomem *base;/* frame engine base address */ +void __iomem *eth_sw_base;/* switch base address */ +void __iomem *sysctrl_base;/* system-controller base address */ + +struct mii_dev *bus; + +struct fe_tx_dma *tx_ring; +struct fe_rx_dma *rx_ring; + +u8 *rx_buf[NUM_RX_DESC ]; + +/* Point to the next RXD DMA wants to use in RXD Ring0 */ +int rx_dma_idx; +/* Point to the next TXD in TXD Ring0 CPU wants to use */ +int tx_dma_idx; +}; + +static int mdio_wait_read (struct mt76xx_eth_dev *priv,u32 mask,bool mask_set) +{ +void __iomem *base = priv->eth_sw_base; +int timeout =CONFIG_MDIO_TIMEOUT ; +int start; +
drivers/net/mt76xx-eth.c line 174
Quoted 10 lines
drivers/net/mt76xx-eth.c new file +10
-0+ start =get_timer (0 ); +while (get_timer (start) < timeout) { +if (mask_set) { +if (readl (base +MT76XX_SWITCH_PCR1 ) & mask) +return 0 ; + }else { +if (!(readl (base +MT76XX_SWITCH_PCR1 ) & mask)) +return 0 ; + } + }
wait_for_bit_le32(base + MT76XX_SWITCH_PCR1, mask, mask_set, CONFIG_MDIO_TIMEOUT, 0) ?
Quoted 102 lines
drivers/net/mt76xx-eth.c new file +102
-0+ +printf ("MDIO operation timeout!\n" ); + +return -ETIMEDOUT ; +} + +static int mii_mgr_read (struct mt76xx_eth_dev *priv, +u32 phy_addr,u32 phy_register,u32 *read_data) +{ +void __iomem *base = priv->eth_sw_base; +u32 status =0 ; +u32 ret; + + *read_data =0xffff ; +/* Make sure previous read operation is complete */ + ret =mdio_wait_read (priv,BIT (1 ), false); +if (ret) +return ret; + +writel (BIT (14 ) | (phy_register <<8 ) | phy_addr, + base +MT76XX_SWITCH_PCR0 ); + +/* Make sure previous read operation is complete */ + ret =mdio_wait_read (priv,BIT (1 ), true); +if (ret) +return ret; + + status =readl (base +MT76XX_SWITCH_PCR1 ); + *read_data = (u32)(status >>16 ); + +return 0 ; +} + +static int mii_mgr_write (struct mt76xx_eth_dev *priv, +u32 phy_addr,u32 phy_register,u32 write_data) +{ +void __iomem *base = priv->eth_sw_base; +u32 data; +int ret; + +/* Make sure previous write operation is complete */ + ret =mdio_wait_read (priv,BIT (0 ), false); +if (ret) +return ret; + + data = (write_data &0xffff ) <<16 ; + data |= (phy_register <<8 ) | phy_addr; + data |=BIT (13 ); +writel (data, base +MT76XX_SWITCH_PCR0 ); + +return mdio_wait_read (priv,BIT (0 ), true); +} + +static int mt76xx_mdio_read (struct mii_dev *bus,int addr,int devad,int reg) +{ +u32 val; +int ret; + + ret =mii_mgr_read (bus->priv, addr, reg, &val); +if (ret) +return ret; + +return val; +} + +static int mt76xx_mdio_write (struct mii_dev *bus,int addr,int devad,int reg, +u16 value) +{ +return mii_mgr_write (bus->priv, addr, reg, value); +} + +static void mt7628_ephy_init (struct mt76xx_eth_dev *priv) +{ +int i; + +mii_mgr_write (priv,0 ,31 ,0x2000 );/* change G2 page */ +mii_mgr_write (priv,0 ,26 ,0x0000 ); + +for (i =0 ; i <5 ; i++) { +mii_mgr_write (priv, i,31 ,0x8000 );/*change L0 page */ +mii_mgr_write (priv, i,0 ,0x3100 ); + +/* EEE disable */ +mii_mgr_write (priv, i,30 ,0xa000 ); +mii_mgr_write (priv, i,31 ,0xa000 );/* change L2 page */ +mii_mgr_write (priv, i,16 ,0x0606 ); +mii_mgr_write (priv, i,23 ,0x0f0e ); +mii_mgr_write (priv, i,24 ,0x1610 ); +mii_mgr_write (priv, i,30 ,0x1f15 ); +mii_mgr_write (priv, i,28 ,0x6111 ); + } + +/* 100Base AOI setting */ +mii_mgr_write (priv,0 ,31 ,0x5000 );/* change G5 page */ +mii_mgr_write (priv,0 ,19 ,0x004a ); +mii_mgr_write (priv,0 ,20 ,0x015a ); +mii_mgr_write (priv,0 ,21 ,0x00ee ); +mii_mgr_write (priv,0 ,22 ,0x0033 ); +mii_mgr_write (priv,0 ,23 ,0x020a ); +mii_mgr_write (priv,0 ,24 ,0x0000 ); +mii_mgr_write (priv,0 ,25 ,0x024a ); +mii_mgr_write (priv,0 ,26 ,0x035a );
drivers/net/mt76xx-eth.c line 286
Quoted 10 lines
drivers/net/mt76xx-eth.c new file +10
-0+mii_mgr_write (priv,0 ,27 ,0x02ee ); +mii_mgr_write (priv,0 ,28 ,0x0233 ); +mii_mgr_write (priv,0 ,29 ,0x000a ); +mii_mgr_write (priv,0 ,30 ,0x0000 ); + +/* Fix EPHY idle state abnormal behavior */ +mii_mgr_write (priv,0 ,31 ,0x4000 );/* change G4 page */ +mii_mgr_write (priv,0 ,29 ,0x000d ); +mii_mgr_write (priv,0 ,30 ,0x0500 ); +}
wouldn't it make more sense to move this to a small PHY driver?
Quoted 24 lines
drivers/net/mt76xx-eth.c new file +24
-0+ +static void rt305x_esw_init (struct mt76xx_eth_dev *priv) +{ +void __iomem *sysctrl_base = priv->sysctrl_base; +void __iomem *base = priv->eth_sw_base; + +/* +* FC_RLS_TH=200, FC_SET_TH=160 +* DROP_RLS=120, DROP_SET_TH=80 +*/ +writel (0xc8a07850 , base +MT76XX_SWITCH_FCT0 ); +writel (0x00000000 , base +MT76XX_SWITCH_SGC2 ); +writel (0x00405555 , base +MT76XX_SWITCH_PFC1 ); +writel (0x00007f7f , base +MT76XX_SWITCH_POC0 ); +writel (0x00007f7f , base +MT76XX_SWITCH_POC2 );/* disable VLAN */ +writel (0x0002500c , base +MT76XX_SWITCH_FCT2 ); +/* hashing algorithm=XOR48, aging interval=300sec */ +writel (0x0008a301 , base +MT76XX_SWITCH_SGC ); +writel (0x02404040 , base +MT76XX_SWITCH_SOCPC ); + +/* Ext PHY Addr=0x1f */ +writel (0x3f502b28 , base +MT76XX_SWITCH_FPA1 ); +writel (0x00000000 , base +MT76XX_SWITCH_FPA ); +/* 1us cycle number=125 (FE's clock=125Mhz) */
drivers/net/mt76xx-eth.c line 320
Quoted 10 lines
drivers/net/mt76xx-eth.c new file +10
-0+writel (0x7d000000 , base +MT76XX_SWITCH_BMU_CTRL ); + +/* Configure analog GPIO setup */ +clrsetbits_le32 (sysctrl_base +MT76XX_AGPIO_CFG_REG , +MT7628_EPHY_P0_DIS ,MT7628_EPHY_GPIO_AIO_EN ); + +/* Reset PHY */ +setbits_le32 (sysctrl_base +MT76XX_RSTCTRL_REG ,RSTCTRL_EPHY_RST ); +clrbits_le32 (sysctrl_base +MT76XX_RSTCTRL_REG ,RSTCTRL_EPHY_RST ); +mdelay (10 );
later you should model the sysctrl sub-system as a syscon device with a reset controller as child device
Quoted 22 lines
drivers/net/mt76xx-eth.c new file +22
-0+ +/* Set P0 EPHY LED mode */ +clrsetbits_le32 (sysctrl_base +MT76XX_GPIO2_MODE_REG , +0x0ffc0ffc ,0x05540554 ); +mdelay (10 ); + +mt7628_ephy_init (priv); +} + +static void eth_dma_start (struct mt76xx_eth_dev *priv) +{ +void __iomem *base = priv->base; + +setbits_le32 (base +PDMA_GLO_CFG ,TX_WB_DDONE |RX_DMA_EN |TX_DMA_EN ); +} + +static void eth_dma_stop (struct mt76xx_eth_dev *priv) +{ +void __iomem *base = priv->base; +int timeout =CONFIG_DMA_STOP_TIMEOUT ; +int start; +u32 val;
drivers/net/mt76xx-eth.c line 352
Quoted 10 lines
drivers/net/mt76xx-eth.c new file +10
-0+ +clrbits_le32 (base +PDMA_GLO_CFG ,TX_WB_DDONE |RX_DMA_EN |TX_DMA_EN ); + +/* Wait for DMA to stop */ + start =get_timer (0 ); +while (get_timer (start) < timeout) { + val =readl (base +PDMA_GLO_CFG ); +if ((val & (RX_DMA_BUSY |TX_DMA_BUSY )) ==0 ) +return ; + }
wait_for_bit_le32() ?
Quoted 36 lines
drivers/net/mt76xx-eth.c new file +36
-0+ +printf ("DMA stop timeout error!\n" ); +} + +static int mt76xx_eth_write_hwaddr (struct udevice *dev) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +void __iomem *base = priv->base; +u8 *addr = ((struct eth_pdata *)dev_get_platdata (dev))->enetaddr; +u32 val; +u16 tmp; + +/* Set MAC address. */ + tmp = (u16 )addr[0 ]; + val = (tmp <<8 ) | addr[1 ]; + +writel (val, base +SDM_MAC_ADRH ); + + tmp = (u16 )addr[2 ]; + val = (tmp <<8 ) | addr[3 ]; + val = val <<16 ; + tmp = (u16 )addr[4 ]; + val |= (tmp <<8 ) | addr[5 ]; +writel (val, base +SDM_MAC_ADRL ); + +return 0 ; +} + +static int mt76xx_eth_send (struct udevice *dev,void *packet,int length) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +void __iomem *base = priv->base; +int ret; +int idx; +int i; +
drivers/net/mt76xx-eth.c line 398
Quoted 10 lines
drivers/net/mt76xx-eth.c new file +10
-0+ idx = priv->tx_dma_idx; + +/* Pad message to a minimum length */ +if (length <PADDING_LENGTH ) { +char *p = (char *)packet; + +for (i =0 ; i <PADDING_LENGTH - length; i++) + p[length + i] =0 ; + length =PADDING_LENGTH ; + }
as this pattern is common, maybe you could add a generic function for that like skb_padto() in Linux
Quoted 63 lines
drivers/net/mt76xx-eth.c new file +63
-0+ +/* Check if buffer is ready for next TX DMA */ + ret =wait_for_bit_le32 (&priv->tx_ring[idx].txd2,TX_DMA_DONE , true, +CONFIG_TX_DMA_TIMEOUT , false); +if (ret) { +printf ("TX: DMA still busy on buffer %d\n" , idx); +return ret; + } + +flush_dcache_range ((u32 )packet, (u32 )packet + length); + + priv->tx_ring[idx].txd1 =CPHYSADDR (packet); + priv->tx_ring[idx].txd2 |=TX_DMA_PLEN0 (length); + priv->tx_ring[idx].txd2 &= ~TX_DMA_DONE ; + + idx = (idx +1 ) %NUM_TX_DESC ; + +/* Make sure the writes exceuted at this place */ +wmb (); +writel (idx, base +TX_CTX_IDX0 ); + + priv->tx_dma_idx = idx; + +return 0 ; +} + +static int mt76xx_eth_recv (struct udevice *dev,int flags,uchar **packetp) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +void __iomem *base = priv->base; +u32 rxd_info; +int length; +int idx; + + idx = priv->rx_dma_idx; + + rxd_info = priv->rx_ring[idx].rxd2; +if ((rxd_info &RX_DMA_DONE ) ==0 ) +return -EAGAIN ; + + length =RX_DMA_GET_PLEN0 (priv->rx_ring[idx].rxd2); +if (length ==0 || length >MTK_QDMA_PAGE_SIZE ) { +printf ("%s: invalid length (%d bytes)\n" , __func__, length); +return -EIO ; + } + + *packetp = priv->rx_buf[idx]; +invalidate_dcache_range ((u32)*packetp, (u32)*packetp + length); + + priv->rx_ring[idx].rxd4 =0 ; + priv->rx_ring[idx].rxd2 =RX_DMA_LSO ; + +/* Make sure the writes exceuted at this place */ +wmb (); + +/* Move point to next RXD which wants to alloc */ +writel (idx, base +RX_CALC_IDX0 ); + +/* Update to Next packet point that was received */ + idx = (idx +1 ) %NUM_RX_DESC ; + + priv->rx_dma_idx = idx; +
drivers/net/mt76xx-eth.c line 471
Quoted 10 lines
drivers/net/mt76xx-eth.c new file +10
-0+return length; +} + +static int phy_link_up (struct mt76xx_eth_dev *priv) +{ +u32 val; + +mii_mgr_read (priv,0x00 ,MII_BMSR , &val); +return !!(val &BMSR_LSTATUS ); +}
with a PHY driver you wouldn't need to do this yourself ;)
Quoted 112 lines
drivers/net/mt76xx-eth.c new file +112
-0+ +static int mt76xx_eth_start (struct udevice *dev) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +void __iomem *base = priv->base; +uchar packet[MTK_QDMA_PAGE_SIZE ]; +uchar *packetp; +int i; + +for (i =0 ; i <NUM_RX_DESC ; i++) { +memset ((void *)&priv->rx_ring[i],0 ,sizeof (priv->rx_ring[0 ])); + priv->rx_ring[i].rxd2 |=RX_DMA_LSO ; + priv->rx_ring[i].rxd1 =CPHYSADDR (priv->rx_buf[i]); + } + +for (i =0 ; i <NUM_TX_DESC ; i++) { +memset ((void *)&priv->tx_ring[i],0 ,sizeof (priv->tx_ring[0 ])); + priv->tx_ring[i].txd2 =TX_DMA_LS0 |TX_DMA_DONE ; + priv->tx_ring[i].txd4 =TX_DMA_PN (1 ); + } + + priv->rx_dma_idx =0 ; + priv->tx_dma_idx =0 ; + +/* Make sure the writes exceuted at this place */ +wmb (); + +/* disable delay interrupt */ +writel (0 , base +DLY_INT_CFG ); + +clrbits_le32 (base +PDMA_GLO_CFG ,0xffff0000 ); + +/* Tell the adapter where the TX/RX rings are located. */ +writel (CPHYSADDR (&priv->rx_ring[0 ]), base +RX_BASE_PTR0 ); +writel (CPHYSADDR ((u32)&priv->tx_ring[0 ]), base +TX_BASE_PTR0 ); + +writel (NUM_RX_DESC , base +RX_MAX_CNT0 ); +writel (NUM_TX_DESC , base +TX_MAX_CNT0 ); + +writel (priv->tx_dma_idx, base +TX_CTX_IDX0 ); +writel (RST_DTX_IDX0 , base +PDMA_RST_IDX ); + +writel (NUM_RX_DESC -1 , base +RX_CALC_IDX0 ); +writel (RST_DRX_IDX0 , base +PDMA_RST_IDX ); + +/* Make sure the writes exceuted at this place */ +wmb (); +eth_dma_start (priv); + +/* Check if link is not up yet */ +if (!phy_link_up (priv)) { +/* Wait for link to come up */ + +printf ("Waiting for link to come up ." ); +for (i =0 ; i < (LINK_TIMEOUT /LINK_DELAY_TIME ); i++) { +mdelay (LINK_DELAY_TIME ); +if (phy_link_up (priv)) { +mdelay (100 );/* Ensure all is ready */ +break ; + } + +printf ("." ); + } + +if (phy_link_up (priv)) +printf (" done\n" ); +else +printf (" timeout! Trying anyways\n" ); + } + +/* +* The integrated switch seems to queue some received ethernet +* packets in some FIFO. Lets read the already queued packets +* out by using the reveice routine, so that these old messages +* are dropped before the new xfer starts. +*/ + packetp = &packet[0 ]; +while (mt76xx_eth_recv (dev,0 , &packetp) != -EAGAIN ) + ; + +return 0 ; +} + +static void mt76xx_eth_stop (struct udevice *dev) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); + +eth_dma_stop (priv); +} + +static int mt76xx_eth_probe (struct udevice *dev) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +const void *blob = gd->fdt_blob; +struct mii_dev *bus; +fdt_addr_t base; +fdt_size_t size; +int node; +int ret; +int i; + +/* Save frame-engine base address for later use */ + priv->base =dev_remap_addr_index (dev,0 ); +if (IS_ERR (priv->base)) +return PTR_ERR (priv->base); + +/* Save switch base address for later use */ + priv->eth_sw_base =dev_remap_addr_index (dev,1 ); +if (IS_ERR (priv->eth_sw_base)) +return PTR_ERR (priv->eth_sw_base); + +/* Get system controller base address */
drivers/net/mt76xx-eth.c line 593
Quoted 10 lines
drivers/net/mt76xx-eth.c new file +10
-0+ node =fdt_node_offset_by_compatible (blob,-1 ,"ralink,mt7620a-sysc" ); +if (node <0 ) +return -FDT_ERR_NOTFOUND ; + + base =fdtdec_get_addr_size_auto_noparent (blob, node,"reg" , +0 , &size, true); +if (base ==FDT_ADDR_T_NONE ) +return -EINVAL ; + + priv->sysctrl_base =ioremap_nocache (base, size);
I think if you add "ralink,mt7620a-sysc" as a generic syscon device, you don't need to write an extra driver and you could get a regmap context for writing sysc registers.
Quoted 56 lines
drivers/net/mt76xx-eth.c new file +55
-0+ +/* Put rx and tx rings into KSEG1 area (uncached) */ + priv->tx_ring = (struct fe_tx_dma *) +KSEG1ADDR (memalign (ARCH_DMA_MINALIGN , +sizeof (*priv->tx_ring) *NUM_TX_DESC )); + priv->rx_ring = (struct fe_rx_dma *) +KSEG1ADDR (memalign (ARCH_DMA_MINALIGN , +sizeof (*priv->rx_ring) *NUM_RX_DESC )); + +for (i =0 ; i <NUM_RX_DESC ; i++) + priv->rx_buf[i] =memalign (PKTALIGN ,MTK_QDMA_PAGE_SIZE ); + + bus =mdio_alloc (); +if (!bus) { +printf ("Failed to allocate MDIO bus\n" ); +return -ENOMEM ; + } + + bus->read = mt76xx_mdio_read; + bus->write = mt76xx_mdio_write; +snprintf (bus->name,sizeof (bus->name), dev->name); + bus->priv = (void *)priv; + + ret =mdio_register (bus); +if (ret) +return ret; + +/* Switch configuration */ +rt305x_esw_init (priv); + +return 0 ; +} + +static const struct eth_ops mt76xx_eth_ops = { + .start = mt76xx_eth_start, + .send = mt76xx_eth_send, + .recv = mt76xx_eth_recv, + .stop = mt76xx_eth_stop, + .write_hwaddr = mt76xx_eth_write_hwaddr, +}; + +static const struct udevice_id mt76xx_eth_ids[] = { + { .compatible ="mediatek,mt7622-eth" }, + { } +}; + +U_BOOT_DRIVER (mt76xx_eth) = { + .name ="mt76xx_eth" , + .id =UCLASS_ETH , + .of_match = mt76xx_eth_ids, + .probe = mt76xx_eth_probe, + .ops = &mt76xx_eth_ops, + .priv_auto_alloc_size =sizeof (struct mt76xx_eth_dev ), + .platdata_auto_alloc_size =sizeof (struct eth_pdata ), +};
Signature · 9 lines
- Daniel -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: OpenPGP digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20181007/5192818c/attachment.sig>
PATCH 1/1 net: Add MT76xx ethernet driver
Hi Daniel,
Quoted 226 lines · Daniel Schwierzeck
Quoted 223 lines · Stefan Roese
This patch adds ethernet support for the Mediatek MT76xx SoC, including a minimum setup of the integrated switch. This driver is loosly based on the driver version included in this MediaTek github repository:
https://github.com/MediaTek-Labs/linkit-smart-uboot.git
Tested on the MT7688 LinkIt smart-gateway and on the Gardena-smart-gateway.
Signed-off-by Stefan Roese <[email protected]>Cc Daniel Schwierzeck <[email protected]>Cc Joe Hershberger <[email protected]>--- drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 + drivers/net/mt76xx-eth.c | 648 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 656 insertions(+)create mode 100644
drivers/net/mt76xx-eth.cdrivers/net/Kconfig +7
-0@@ -227,6 +227,13 @@ config MACB_ZYNQ The Cadence MACB ethernet interface was used on Zynq platform. Say Y to enable support for the MACB/GEM in Zynq chip. +config MT76XX_ETH + bool "MediaTek MT76xx Ethernet Interface" + depends on ARCH_MT7620 + help + The MediaTek MT76xx ethernet interface is used on MT7688 + based boards. + config PCH_GBE bool "Intel Platform Controller Hub EG20T GMAC driver" depends on DM_ETH && DM_PCIdrivers/net/Makefile +1
-0@@ -37,6 +37,7 @@ obj-$(CONFIG_LPC32XX_ETH) += lpc32xx_eth.o obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o +obj-$(CONFIG_MT76XX_ETH) += mt76xx-eth.o obj-$(CONFIG_MVGBE) += mvgbe.o obj-$(CONFIG_MVNETA) += mvneta.o obj-$(CONFIG_MVPP2) += mvpp2.odrivers/net/mt76xx-eth.c new file +168
-0@@ -0,0 +1,648 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* +* MediaTek ethernet IP driver for U-Boot +* +* Copyright (C) 2018 Stefan Roese <[email protected]> +* +* This code is mostly based on the code extracted from this MediaTek +* github repository: +* +* https://github.com/MediaTek-Labs/linkit-smart-uboot.git +* +* I was not able to find a specific license or other developers +* copyrights here, so I can't add them here. +*/ + +#include <common.h> +#include <dm.h> +#include <malloc.h> +#include <miiphy.h> +#include <net.h> +#include <wait_bit.h> +#include <asm/io.h> +#include <linux/err.h> + +/* System controller register */ +#define MT76XX_RSTCTRL_REG 0x34 +#define RSTCTRL_EPHY_RST BIT(24) + +#define MT76XX_AGPIO_CFG_REG 0x3c +#define MT7628_EPHY_GPIO_AIO_EN GENMASK(20, 17) +#define MT7628_EPHY_P0_DIS BIT(16) + +#define MT76XX_GPIO2_MODE_REG 0x64 + +/* Ethernet frame engine register */ +#define PDMA_RELATED 0x0800 + +#define TX_BASE_PTR0 (PDMA_RELATED + 0x000) +#define TX_MAX_CNT0 (PDMA_RELATED + 0x004) +#define TX_CTX_IDX0 (PDMA_RELATED + 0x008) +#define TX_DTX_IDX0 (PDMA_RELATED + 0x00c) + +#define RX_BASE_PTR0 (PDMA_RELATED + 0x100) +#define RX_MAX_CNT0 (PDMA_RELATED + 0x104) +#define RX_CALC_IDX0 (PDMA_RELATED + 0x108) + +#define PDMA_GLO_CFG (PDMA_RELATED + 0x204) +#define PDMA_RST_IDX (PDMA_RELATED + 0x208) +#define DLY_INT_CFG (PDMA_RELATED + 0x20c) + +#define SDM_RELATED 0x0c00 + +#define SDM_MAC_ADRL (SDM_RELATED + 0x0c)/* MAC address LSB */ +#define SDM_MAC_ADRH (SDM_RELATED + 0x10)/* MAC Address MSB */ + +#define RST_DTX_IDX0 BIT(0) +#define RST_DRX_IDX0 BIT(16) + +#define TX_DMA_EN BIT(0) +#define TX_DMA_BUSY BIT(1) +#define RX_DMA_EN BIT(2) +#define RX_DMA_BUSY BIT(3) +#define TX_WB_DDONE BIT(6) + +/* Ethernet switch register */ +#define MT76XX_SWITCH_FCT0 0x0008 +#define MT76XX_SWITCH_PFC1 0x0014 +#define MT76XX_SWITCH_FPA 0x0084 +#define MT76XX_SWITCH_SOCPC 0x008c +#define MT76XX_SWITCH_POC0 0x0090 +#define MT76XX_SWITCH_POC2 0x0098 +#define MT76XX_SWITCH_SGC 0x009c +#define MT76XX_SWITCH_PCR0 0x00c0 +#define MT76XX_SWITCH_PCR1 0x00c4 +#define MT76XX_SWITCH_FPA1 0x00c8 +#define MT76XX_SWITCH_FCT2 0x00cc +#define MT76XX_SWITCH_SGC2 0x00e4 +#define MT76XX_SWITCH_BMU_CTRL 0x0110 + +/* rxd2 */ +#define RX_DMA_DONE BIT(31) +#define RX_DMA_LSO BIT(30) +#define RX_DMA_PLEN0 (_x) (((_x) & 0x3fff) << 16) +#define RX_DMA_GET_PLEN0 (_x) (((_x) >> 16) & 0x3fff) +#define RX_DMA_TAG BIT(15) +/* rxd3 */ +#define RX_DMA_TPID (_x) (((_x) >> 16) & 0xffff) +#define RX_DMA_VID (_x) ((_x) & 0xffff) +/* rxd4 */ +#define RX_DMA_L4VALID BIT(30) + +struct fe_rx_dma { +unsigned int rxd1; +unsigned int rxd2; +unsigned int rxd3; +unsigned int rxd4; +} __packed__aligned(4) ; + +#define TX_DMA_BUF_LEN 0x3fff +#define TX_DMA_PLEN0_MASK (TX_DMA_BUF_LEN << 16) +#define TX_DMA_PLEN0 (_x) (((_x) & TX_DMA_BUF_LEN) << 16) +#define TX_DMA_PLEN1 (_x) ((_x) & TX_DMA_BUF_LEN) +#define TX_DMA_GET_PLEN0 (_x) (((_x) >> 16) & TX_DMA_BUF_LEN) +#define TX_DMA_GET_PLEN1 (_x) ((_x) & TX_DMA_BUF_LEN) +#define TX_DMA_LS1 BIT(14) +#define TX_DMA_LS0 BIT(30) +#define TX_DMA_DONE BIT(31) + +#define TX_DMA_INS_VLAN_MT7621 BIT(16) +#define TX_DMA_INS_VLAN BIT(7) +#define TX_DMA_INS_PPPOE BIT(12) +#define TX_DMA_QN (_x) ((_x) << 16) +#define TX_DMA_PN (_x) ((_x) << 24) +#define TX_DMA_QN_MASK TX_DMA_QN(0x7) +#define TX_DMA_PN_MASK TX_DMA_PN(0x7) +#define TX_DMA_UDF BIT(20) +#define TX_DMA_CHKSUM (0x7 << 29) +#define TX_DMA_TSO BIT(28) + +struct fe_tx_dma { +unsigned int txd1; +unsigned int txd2; +unsigned int txd3; +unsigned int txd4; +} __packed__aligned(4) ; + +#define NUM_RX_DESC 256 +#define NUM_TX_DESC 4 + +#define PADDING_LENGTH 60 + +#define MTK_QDMA_PAGE_SIZE 2048 + +#define CONFIG_MDIO_TIMEOUT 100 +#define CONFIG_DMA_STOP_TIMEOUT 100 +#define CONFIG_TX_DMA_TIMEOUT 100 + +#define LINK_DELAY_TIME 500/* 500 ms */ +#define LINK_TIMEOUT 10000/* 10 seconds */ + +struct mt76xx_eth_dev { +void __iomem *base;/* frame engine base address */ +void __iomem *eth_sw_base;/* switch base address */ +void __iomem *sysctrl_base;/* system-controller base address */ + +struct mii_dev *bus; + +struct fe_tx_dma *tx_ring; +struct fe_rx_dma *rx_ring; + +u8 *rx_buf[NUM_RX_DESC ]; + +/* Point to the next RXD DMA wants to use in RXD Ring0 */ +int rx_dma_idx; +/* Point to the next TXD in TXD Ring0 CPU wants to use */ +int tx_dma_idx; +}; + +static int mdio_wait_read (struct mt76xx_eth_dev *priv,u32 mask,bool mask_set) +{ +void __iomem *base = priv->eth_sw_base; +int timeout =CONFIG_MDIO_TIMEOUT ; +int start; + + start =get_timer (0 ); +while (get_timer (start) < timeout) { +if (mask_set) { +if (readl (base +MT76XX_SWITCH_PCR1 ) & mask)
Quoted 8 lines
drivers/net/mt76xx-eth.c line 174
Quoted 6 lines
drivers/net/mt76xx-eth.c new file +6
-0+return 0 ; + }else { +if (!(readl (base +MT76XX_SWITCH_PCR1 ) & mask)) +return 0 ; + } + }
wait_for_bit_le32(base + MT76XX_SWITCH_PCR1, mask, mask_set, CONFIG_MDIO_TIMEOUT, 0)?
Yes, thanks. Will change in v2.
Quoted 107 lines
Quoted 107 lines
drivers/net/mt76xx-eth.c new file +106
-0+ +printf ("MDIO operation timeout!\n" ); + +return -ETIMEDOUT ; +} + +static int mii_mgr_read (struct mt76xx_eth_dev *priv, +u32 phy_addr,u32 phy_register,u32 *read_data) +{ +void __iomem *base = priv->eth_sw_base; +u32 status =0 ; +u32 ret; + + *read_data =0xffff ; +/* Make sure previous read operation is complete */ + ret =mdio_wait_read (priv,BIT (1 ), false); +if (ret) +return ret; + +writel (BIT (14 ) | (phy_register <<8 ) | phy_addr, + base +MT76XX_SWITCH_PCR0 ); + +/* Make sure previous read operation is complete */ + ret =mdio_wait_read (priv,BIT (1 ), true); +if (ret) +return ret; + + status =readl (base +MT76XX_SWITCH_PCR1 ); + *read_data = (u32)(status >>16 ); + +return 0 ; +} + +static int mii_mgr_write (struct mt76xx_eth_dev *priv, +u32 phy_addr,u32 phy_register,u32 write_data) +{ +void __iomem *base = priv->eth_sw_base; +u32 data; +int ret; + +/* Make sure previous write operation is complete */ + ret =mdio_wait_read (priv,BIT (0 ), false); +if (ret) +return ret; + + data = (write_data &0xffff ) <<16 ; + data |= (phy_register <<8 ) | phy_addr; + data |=BIT (13 ); +writel (data, base +MT76XX_SWITCH_PCR0 ); + +return mdio_wait_read (priv,BIT (0 ), true); +} + +static int mt76xx_mdio_read (struct mii_dev *bus,int addr,int devad,int reg) +{ +u32 val; +int ret; + + ret =mii_mgr_read (bus->priv, addr, reg, &val); +if (ret) +return ret; + +return val; +} + +static int mt76xx_mdio_write (struct mii_dev *bus,int addr,int devad,int reg, +u16 value) +{ +return mii_mgr_write (bus->priv, addr, reg, value); +} + +static void mt7628_ephy_init (struct mt76xx_eth_dev *priv) +{ +int i; + +mii_mgr_write (priv,0 ,31 ,0x2000 );/* change G2 page */ +mii_mgr_write (priv,0 ,26 ,0x0000 ); + +for (i =0 ; i <5 ; i++) { +mii_mgr_write (priv, i,31 ,0x8000 );/*change L0 page */ +mii_mgr_write (priv, i,0 ,0x3100 ); + +/* EEE disable */ +mii_mgr_write (priv, i,30 ,0xa000 ); +mii_mgr_write (priv, i,31 ,0xa000 );/* change L2 page */ +mii_mgr_write (priv, i,16 ,0x0606 ); +mii_mgr_write (priv, i,23 ,0x0f0e ); +mii_mgr_write (priv, i,24 ,0x1610 ); +mii_mgr_write (priv, i,30 ,0x1f15 ); +mii_mgr_write (priv, i,28 ,0x6111 ); + } + +/* 100Base AOI setting */ +mii_mgr_write (priv,0 ,31 ,0x5000 );/* change G5 page */ +mii_mgr_write (priv,0 ,19 ,0x004a ); +mii_mgr_write (priv,0 ,20 ,0x015a ); +mii_mgr_write (priv,0 ,21 ,0x00ee ); +mii_mgr_write (priv,0 ,22 ,0x0033 ); +mii_mgr_write (priv,0 ,23 ,0x020a ); +mii_mgr_write (priv,0 ,24 ,0x0000 ); +mii_mgr_write (priv,0 ,25 ,0x024a ); +mii_mgr_write (priv,0 ,26 ,0x035a ); +mii_mgr_write (priv,0 ,27 ,0x02ee ); +mii_mgr_write (priv,0 ,28 ,0x0233 ); +mii_mgr_write (priv,0 ,29 ,0x000a ); +mii_mgr_write (priv,0 ,30 ,0x0000 );
Quoted 8 lines
drivers/net/mt76xx-eth.c line 286
Quoted 6 lines
drivers/net/mt76xx-eth.c new file +6
-0+ +/* Fix EPHY idle state abnormal behavior */ +mii_mgr_write (priv,0 ,31 ,0x4000 );/* change G4 page */ +mii_mgr_write (priv,0 ,29 ,0x000d ); +mii_mgr_write (priv,0 ,30 ,0x0500 ); +}wouldn't it make more sense to move this to a small PHY driver?
I would like to not do this right now. Perhaps if time permits, I can do this at a later time. Or someone else jumps in. My hope is, that some other MT76xx MIPS users will join the mainline U-Boot development at some time. :)
Quoted 28 lines
Quoted 28 lines
drivers/net/mt76xx-eth.c new file +28
-0+ +static void rt305x_esw_init (struct mt76xx_eth_dev *priv) +{ +void __iomem *sysctrl_base = priv->sysctrl_base; +void __iomem *base = priv->eth_sw_base; + +/* +* FC_RLS_TH=200, FC_SET_TH=160 +* DROP_RLS=120, DROP_SET_TH=80 +*/ +writel (0xc8a07850 , base +MT76XX_SWITCH_FCT0 ); +writel (0x00000000 , base +MT76XX_SWITCH_SGC2 ); +writel (0x00405555 , base +MT76XX_SWITCH_PFC1 ); +writel (0x00007f7f , base +MT76XX_SWITCH_POC0 ); +writel (0x00007f7f , base +MT76XX_SWITCH_POC2 );/* disable VLAN */ +writel (0x0002500c , base +MT76XX_SWITCH_FCT2 ); +/* hashing algorithm=XOR48, aging interval=300sec */ +writel (0x0008a301 , base +MT76XX_SWITCH_SGC ); +writel (0x02404040 , base +MT76XX_SWITCH_SOCPC ); + +/* Ext PHY Addr=0x1f */ +writel (0x3f502b28 , base +MT76XX_SWITCH_FPA1 ); +writel (0x00000000 , base +MT76XX_SWITCH_FPA ); +/* 1us cycle number=125 (FE's clock=125Mhz) */ +writel (0x7d000000 , base +MT76XX_SWITCH_BMU_CTRL ); + +/* Configure analog GPIO setup */ + clrsetbits_le32(sysctrl_base + MT76XX_AGPIO_CFG_REG,
Quoted 8 lines
drivers/net/mt76xx-eth.c line 320
Quoted 6 lines
drivers/net/mt76xx-eth.c new file +6
-0+ MT7628_EPHY_P0_DIS, MT7628_EPHY_GPIO_AIO_EN); + +/* Reset PHY */ +setbits_le32 (sysctrl_base +MT76XX_RSTCTRL_REG ,RSTCTRL_EPHY_RST ); +clrbits_le32 (sysctrl_base +MT76XX_RSTCTRL_REG ,RSTCTRL_EPHY_RST ); +mdelay (10 );later you should model the sysctrl sub-system as a syscon device with a reset controller as child device
I've changed this to use syscon / regmap in v2.
Quoted 26 lines
Quoted 26 lines
drivers/net/mt76xx-eth.c new file +26
-0+ +/* Set P0 EPHY LED mode */ +clrsetbits_le32 (sysctrl_base +MT76XX_GPIO2_MODE_REG , +0x0ffc0ffc ,0x05540554 ); +mdelay (10 ); + +mt7628_ephy_init (priv); +} + +static void eth_dma_start (struct mt76xx_eth_dev *priv) +{ +void __iomem *base = priv->base; + +setbits_le32 (base +PDMA_GLO_CFG ,TX_WB_DDONE |RX_DMA_EN |TX_DMA_EN ); +} + +static void eth_dma_stop (struct mt76xx_eth_dev *priv) +{ +void __iomem *base = priv->base; +int timeout =CONFIG_DMA_STOP_TIMEOUT ; +int start; +u32 val; + +clrbits_le32 (base +PDMA_GLO_CFG ,TX_WB_DDONE |RX_DMA_EN |TX_DMA_EN ); + +/* Wait for DMA to stop */
Quoted 8 lines
drivers/net/mt76xx-eth.c line 352
Quoted 6 lines
drivers/net/mt76xx-eth.c new file +6
-0+ start =get_timer (0 ); +while (get_timer (start) < timeout) { + val =readl (base +PDMA_GLO_CFG ); +if ((val & (RX_DMA_BUSY |TX_DMA_BUSY )) ==0 ) +return ; + }
wait_for_bit_le32()?
Done in v2.
Quoted 40 lines
Quoted 40 lines
drivers/net/mt76xx-eth.c new file +40
-0+ +printf ("DMA stop timeout error!\n" ); +} + +static int mt76xx_eth_write_hwaddr (struct udevice *dev) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +void __iomem *base = priv->base; +u8 *addr = ((struct eth_pdata *)dev_get_platdata (dev))->enetaddr; +u32 val; +u16 tmp; + +/* Set MAC address. */ + tmp = (u16 )addr[0 ]; + val = (tmp <<8 ) | addr[1 ]; + +writel (val, base +SDM_MAC_ADRH ); + + tmp = (u16 )addr[2 ]; + val = (tmp <<8 ) | addr[3 ]; + val = val <<16 ; + tmp = (u16 )addr[4 ]; + val |= (tmp <<8 ) | addr[5 ]; +writel (val, base +SDM_MAC_ADRL ); + +return 0 ; +} + +static int mt76xx_eth_send (struct udevice *dev,void *packet,int length) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +void __iomem *base = priv->base; +int ret; +int idx; +int i; + + idx = priv->tx_dma_idx; + +/* Pad message to a minimum length */ +if (length <PADDING_LENGTH ) {
Quoted 8 lines
drivers/net/mt76xx-eth.c line 398
Quoted 6 lines
drivers/net/mt76xx-eth.c new file +6
-0+char *p = (char *)packet; + +for (i =0 ; i <PADDING_LENGTH - length; i++) + p[length + i] =0 ; + length =PADDING_LENGTH ; + }as this pattern is common, maybe you could add a generic function for that like
skb_padto()in Linux
I thought about this as well. But I can't find any other PAD users in U-Boot right now. Again, if really necessary I can come up with such a common implementation at a later time.
Quoted 192 lines
Quoted 63 lines
drivers/net/mt76xx-eth.c new file +63
-0+ +/* Check if buffer is ready for next TX DMA */ + ret =wait_for_bit_le32 (&priv->tx_ring[idx].txd2,TX_DMA_DONE , true, +CONFIG_TX_DMA_TIMEOUT , false); +if (ret) { +printf ("TX: DMA still busy on buffer %d\n" , idx); +return ret; + } + +flush_dcache_range ((u32 )packet, (u32 )packet + length); + + priv->tx_ring[idx].txd1 =CPHYSADDR (packet); + priv->tx_ring[idx].txd2 |=TX_DMA_PLEN0 (length); + priv->tx_ring[idx].txd2 &= ~TX_DMA_DONE ; + + idx = (idx +1 ) %NUM_TX_DESC ; + +/* Make sure the writes exceuted at this place */ +wmb (); +writel (idx, base +TX_CTX_IDX0 ); + + priv->tx_dma_idx = idx; + +return 0 ; +} + +static int mt76xx_eth_recv (struct udevice *dev,int flags,uchar **packetp) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +void __iomem *base = priv->base; +u32 rxd_info; +int length; +int idx; + + idx = priv->rx_dma_idx; + + rxd_info = priv->rx_ring[idx].rxd2; +if ((rxd_info &RX_DMA_DONE ) ==0 ) +return -EAGAIN ; + + length =RX_DMA_GET_PLEN0 (priv->rx_ring[idx].rxd2); +if (length ==0 || length >MTK_QDMA_PAGE_SIZE ) { +printf ("%s: invalid length (%d bytes)\n" , __func__, length); +return -EIO ; + } + + *packetp = priv->rx_buf[idx]; +invalidate_dcache_range ((u32)*packetp, (u32)*packetp + length); + + priv->rx_ring[idx].rxd4 =0 ; + priv->rx_ring[idx].rxd2 =RX_DMA_LSO ; + +/* Make sure the writes exceuted at this place */ +wmb (); + +/* Move point to next RXD which wants to alloc */ +writel (idx, base +RX_CALC_IDX0 ); + +/* Update to Next packet point that was received */ + idx = (idx +1 ) %NUM_RX_DESC ; + + priv->rx_dma_idx = idx; +drivers/net/mt76xx-eth.c line 471
Quoted 10 lines
drivers/net/mt76xx-eth.c new file +10
-0+return length; +} + +static int phy_link_up (struct mt76xx_eth_dev *priv) +{ +u32 val; + +mii_mgr_read (priv,0x00 ,MII_BMSR , &val); +return !!(val &BMSR_LSTATUS ); +}with a PHY driver you wouldn't need to do this yourself ;)
Quoted 116 lines
drivers/net/mt76xx-eth.c new file +116
-0+ +static int mt76xx_eth_start (struct udevice *dev) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +void __iomem *base = priv->base; +uchar packet[MTK_QDMA_PAGE_SIZE ]; +uchar *packetp; +int i; + +for (i =0 ; i <NUM_RX_DESC ; i++) { +memset ((void *)&priv->rx_ring[i],0 ,sizeof (priv->rx_ring[0 ])); + priv->rx_ring[i].rxd2 |=RX_DMA_LSO ; + priv->rx_ring[i].rxd1 =CPHYSADDR (priv->rx_buf[i]); + } + +for (i =0 ; i <NUM_TX_DESC ; i++) { +memset ((void *)&priv->tx_ring[i],0 ,sizeof (priv->tx_ring[0 ])); + priv->tx_ring[i].txd2 =TX_DMA_LS0 |TX_DMA_DONE ; + priv->tx_ring[i].txd4 =TX_DMA_PN (1 ); + } + + priv->rx_dma_idx =0 ; + priv->tx_dma_idx =0 ; + +/* Make sure the writes exceuted at this place */ +wmb (); + +/* disable delay interrupt */ +writel (0 , base +DLY_INT_CFG ); + +clrbits_le32 (base +PDMA_GLO_CFG ,0xffff0000 ); + +/* Tell the adapter where the TX/RX rings are located. */ +writel (CPHYSADDR (&priv->rx_ring[0 ]), base +RX_BASE_PTR0 ); +writel (CPHYSADDR ((u32)&priv->tx_ring[0 ]), base +TX_BASE_PTR0 ); + +writel (NUM_RX_DESC , base +RX_MAX_CNT0 ); +writel (NUM_TX_DESC , base +TX_MAX_CNT0 ); + +writel (priv->tx_dma_idx, base +TX_CTX_IDX0 ); +writel (RST_DTX_IDX0 , base +PDMA_RST_IDX ); + +writel (NUM_RX_DESC -1 , base +RX_CALC_IDX0 ); +writel (RST_DRX_IDX0 , base +PDMA_RST_IDX ); + +/* Make sure the writes exceuted at this place */ +wmb (); +eth_dma_start (priv); + +/* Check if link is not up yet */ +if (!phy_link_up (priv)) { +/* Wait for link to come up */ + +printf ("Waiting for link to come up ." ); +for (i =0 ; i < (LINK_TIMEOUT /LINK_DELAY_TIME ); i++) { +mdelay (LINK_DELAY_TIME ); +if (phy_link_up (priv)) { +mdelay (100 );/* Ensure all is ready */ +break ; + } + +printf ("." ); + } + +if (phy_link_up (priv)) +printf (" done\n" ); +else +printf (" timeout! Trying anyways\n" ); + } + +/* +* The integrated switch seems to queue some received ethernet +* packets in some FIFO. Lets read the already queued packets +* out by using the reveice routine, so that these old messages +* are dropped before the new xfer starts. +*/ + packetp = &packet[0 ]; +while (mt76xx_eth_recv (dev,0 , &packetp) != -EAGAIN ) + ; + +return 0 ; +} + +static void mt76xx_eth_stop (struct udevice *dev) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); + +eth_dma_stop (priv); +} + +static int mt76xx_eth_probe (struct udevice *dev) +{ +struct mt76xx_eth_dev *priv =dev_get_priv (dev); +const void *blob = gd->fdt_blob; +struct mii_dev *bus; +fdt_addr_t base; +fdt_size_t size; +int node; +int ret; +int i; + +/* Save frame-engine base address for later use */ + priv->base =dev_remap_addr_index (dev,0 ); +if (IS_ERR (priv->base)) +return PTR_ERR (priv->base); + +/* Save switch base address for later use */ + priv->eth_sw_base =dev_remap_addr_index (dev,1 ); +if (IS_ERR (priv->eth_sw_base)) +return PTR_ERR (priv->eth_sw_base); + +/* Get system controller base address */ + node =fdt_node_offset_by_compatible (blob,-1 ,"ralink,mt7620a-sysc" ); +if (node <0 ) +return -FDT_ERR_NOTFOUND ; +
Quoted 8 lines
drivers/net/mt76xx-eth.c line 593
Quoted 6 lines
drivers/net/mt76xx-eth.c new file +6
-0+ base =fdtdec_get_addr_size_auto_noparent (blob, node,"reg" , +0 , &size, true); +if (base ==FDT_ADDR_T_NONE ) +return -EINVAL ; + + priv->sysctrl_base =ioremap_nocache (base, size);I think if you add "ralink,mt7620a-sysc" as a generic syscon device, you don't need to write an extra driver and you could get a regmap context for writing sysc registers.
I've changed this to use syscon / regmap in v2.
Thanks for the review,
Stefan