The LS1021A-IOR is a NXP reference board.
Currently supported:

    - DDR3 RAM fixed settings
    - UART
    - SPI boot
    - One SGMII network ports

Signed-off-by: Renaud Barbier <[email protected]>
---
 arch/arm/boards/Makefile                      |   1 +
 arch/arm/boards/ls1021aiot/Makefile           |   3 +
 arch/arm/boards/ls1021aiot/board.c            |  83 +++++++
 arch/arm/boards/ls1021aiot/lowlevel.c         | 121 ++++++++++
 arch/arm/boards/ls1021aiot/ls102xa_pbi.cfg    |  11 +
 .../boards/ls1021aiot/ls102xa_rcw_sd_qspi.cfg |   8 +
 arch/arm/boards/ls1021aiot/start.S            |  11 +
 arch/arm/configs/layerscape_v7_defconfig      | 100 +++++++++
 arch/arm/dts/fsl-ls1021a-iot.dts              | 124 ++++++++++
 arch/arm/lib32/Makefile                       |   1 +
 arch/arm/lib32/pbl.c                          |  21 ++
 drivers/net/Kconfig                           |   2 +-
 drivers/net/gianfar.c                         | 211 ++++++++++++++++--
 drivers/net/gianfar.h                         |  16 +-
 14 files changed, 690 insertions(+), 23 deletions(-)
 create mode 100644 arch/arm/boards/ls1021aiot/Makefile
 create mode 100644 arch/arm/boards/ls1021aiot/board.c
 create mode 100644 arch/arm/boards/ls1021aiot/lowlevel.c
 create mode 100644 arch/arm/boards/ls1021aiot/ls102xa_pbi.cfg
 create mode 100644 arch/arm/boards/ls1021aiot/ls102xa_rcw_sd_qspi.cfg
 create mode 100644 arch/arm/boards/ls1021aiot/start.S
 create mode 100644 arch/arm/configs/layerscape_v7_defconfig
 create mode 100644 arch/arm/dts/fsl-ls1021a-iot.dts
 create mode 100644 arch/arm/lib32/pbl.c

diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile
index f47aea6602..b148c8c1c1 100644
--- a/arch/arm/boards/Makefile
+++ b/arch/arm/boards/Makefile
@@ -192,6 +192,7 @@ obj-$(CONFIG_MACH_ZII_IMX7D_DEV)            += 
zii-imx7d-dev/
 obj-$(CONFIG_MACH_WAGO_PFC_AM35XX)             += wago-pfc-am35xx/
 obj-$(CONFIG_MACH_LS1046ARDB)                  += ls1046ardb/
 obj-$(CONFIG_MACH_TQMLS1046A)                  += tqmls1046a/
+obj-$(CONFIG_MACH_LS1021AIOT)                  += ls1021aiot/
 obj-$(CONFIG_MACH_MNT_REFORM)                  += mnt-reform/
 obj-$(CONFIG_MACH_SKOV_ARM9CPU)                        += skov-arm9cpu/
 obj-$(CONFIG_MACH_RK3568_EVB)                  += rockchip-rk3568-evb/
diff --git a/arch/arm/boards/ls1021aiot/Makefile 
b/arch/arm/boards/ls1021aiot/Makefile
new file mode 100644
index 0000000000..df69ce814b
--- /dev/null
+++ b/arch/arm/boards/ls1021aiot/Makefile
@@ -0,0 +1,3 @@
+lwl-y += lowlevel.o
+obj-y += board.o
+lwl-y += start.o
diff --git a/arch/arm/boards/ls1021aiot/board.c 
b/arch/arm/boards/ls1021aiot/board.c
new file mode 100644
index 0000000000..8f99f1a996
--- /dev/null
+++ b/arch/arm/boards/ls1021aiot/board.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-FileCopyrightText: (C) Copyright 2021 Ametek Inc.
+// SPDX-FileCopyrightText: 2021 Renaud Barbier <[email protected]>,
+
+#include <common.h>
+#include <init.h>
+#include <bbu.h>
+#include <net.h>
+#include <crc.h>
+#include <fs.h>
+#include <io.h>
+#include <envfs.h>
+#include <libfile.h>
+#include <asm/memory.h>
+#include <linux/sizes.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <asm/system.h>
+#include <mach/layerscape.h>
+#include <of_address.h>
+#include <soc/fsl/immap_ls102xa.h>
+
+
+/* Currently 1000FD is not working. Below is a bit of guess work
+ * from reading MMD3/MMD7 of the AR8033
+ */
+static int phy_fixup(struct phy_device *phydev)
+{
+       unsigned short val;
+       int advertise = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half;
+
+       phydev->advertising &= ~advertise;
+
+       /* Ar8031 phy SmartEEE feature cause link status generates glitch,
+        * which cause ethernet link down/up issue, so disable SmartEEE
+        */
+       phy_write(phydev, 0xd, 0x3);
+       phy_write(phydev, 0xe, 0x805d);
+       phy_write(phydev, 0xd, 0x4003);
+       val = phy_read(phydev, 0xe);
+       val &= ~(0x1 << 8);
+       phy_write(phydev, 0xe, val);
+
+       /* Use XTAL */
+       phy_write(phydev, 0xd, 0x7);
+       phy_write(phydev, 0xe, 0x8016);
+       phy_write(phydev, 0xd, 0x4007);
+       val = phy_read(phydev, 0xe);
+       val &= 0xffe3;
+       phy_write(phydev, 0xe, val);
+
+       return 0;
+}
+
+static int iot_mem_init(void)
+{
+       if (!of_machine_is_compatible("fsl,ls1021a"))
+               return 0;
+
+       arm_add_mem_device("ram0", 0x80000000, 0x40000000);
+
+       return 0;
+}
+mem_initcall(iot_mem_init);
+
+#define PHY_ID_AR8031  0x004dd074
+static int iot_postcore_init(void)
+{
+       struct ccsr_scfg *scfg = IOMEM(LS102XA_SCFG_ADDR);
+
+       if (!of_machine_is_compatible("fsl,ls1021a"))
+               return 0;
+
+       /* clear BD & FR bits for BE BD's and frame data */
+       clrbits_be32(&scfg->etsecdmamcr, SCFG_ETSECDMAMCR_LE_BD_FR);
+       out_be32(&scfg->etsecmcr, SCFG_ETSECCMCR_GE2_CLK125);
+
+       phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff, phy_fixup);
+
+       return 0;
+}
+
+coredevice_initcall(iot_postcore_init);
diff --git a/arch/arm/boards/ls1021aiot/lowlevel.c 
b/arch/arm/boards/ls1021aiot/lowlevel.c
new file mode 100644
index 0000000000..d2e0332da8
--- /dev/null
+++ b/arch/arm/boards/ls1021aiot/lowlevel.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0+
+// SPDX-FileCopyrightText: (C) Copyright 2021 Ametek Inc.
+// SPDX-FileCopyrightText: 2021 Renaud Barbier <[email protected]>
+
+/*
+ * Derived from Freescale LSDK-19.09-update-311219
+ */
+#include <common.h>
+#include <clock.h>
+#include <debug_ll.h>
+#include <image-metadata.h>
+#include <platform_data/mmc-esdhc-imx.h>
+#include <soc/fsl/fsl_ddr_sdram.h>
+#include <asm/barebox-arm-head.h>
+#include <asm/barebox-arm.h>
+#include <asm/syscounter.h>
+#include <asm/system.h>
+#include <asm/cache.h>
+#include <linux/sizes.h>
+#include <mach/errata.h>
+#include <mach/lowlevel.h>
+#include <mach/xload.h>
+#include <mach/layerscape.h>
+
+static struct fsl_ddr_controller ddrc[] = {
+       {
+       .memctl_opts.ddrtype = SDRAM_TYPE_DDR3,
+       .base = IOMEM(LS102XA_DDR_ADDR),
+       .ddr_freq = LS1021A_DDR_FREQ,
+       .erratum_A009942 = 1,
+       .chip_selects_per_ctrl = 4,
+       .fsl_ddr_config_reg = {
+               .cs[0].bnds         = 0x008000bf,
+               .cs[0].config       = 0x80014302,
+               .cs[0].config_2     = 0x00000000,
+               .cs[1].bnds         = 0x00000000,
+               .cs[1].config       = 0x00000000,
+               .cs[1].config_2     = 0x00000000,
+               .cs[2].bnds         = 0x00000000,
+               .cs[2].config       = 0x00000000,
+               .cs[2].config_2     = 0x00000000,
+               .cs[3].bnds         = 0x00000000,
+               .cs[3].config       = 0x00000000,
+               .cs[3].config_2     = 0x00000000,
+               .timing_cfg_3       = 0x010e1000,
+               .timing_cfg_0       = 0x50550004,
+               .timing_cfg_1       = 0xbcb38c56,
+               .timing_cfg_2       = 0x0040d120,
+               .ddr_sdram_cfg      = 0x470c0008,
+               .ddr_sdram_cfg_2    = 0x00401010,
+               .ddr_sdram_mode     = 0x00061c60,
+               .ddr_sdram_mode_2   = 0x00180000,
+               .ddr_sdram_interval = 0x18600618,
+               .ddr_data_init      = 0xDEADBEEF,
+               .ddr_sdram_clk_cntl = 0x02000000,
+               .ddr_init_addr      = 0x00000000,
+               .ddr_init_ext_addr  = 0x00000000,
+               .timing_cfg_4       = 0x00000001,
+               .timing_cfg_5       = 0x03401400,
+               .ddr_zq_cntl        = 0x89080600,
+               .ddr_wrlvl_cntl     = 0x8655f605,
+               .ddr_wrlvl_cntl_2   = 0x05060607,
+               .ddr_wrlvl_cntl_3   = 0x05050505,
+               .ddr_sr_cntr        = 0x00000000,
+               .ddr_sdram_rcw_1    = 0x00000000,
+               .ddr_sdram_rcw_2    = 0x00000000,
+               .ddr_sdram_rcw_3    = 0x00000000,
+               .ddr_cdr1           = 0x80040000,
+               .ddr_cdr2           = 0x000000C0,
+               .dq_map_0           = 0x00000000,
+               .dq_map_1           = 0x00000000,
+               .dq_map_2           = 0x00000000,
+               .dq_map_3           = 0x00000000,
+               .debug[28]          = 0x00700046,
+               },
+       },
+};
+
+extern char __dtb_fsl_ls1021a_iot_start[];
+
+static noinline __noreturn void ls1021aiot_r_entry(void)
+{
+       unsigned long membase = LS1021A_DDR_SDRAM_BASE;
+
+       if (get_pc() >= membase) {
+               barebox_arm_entry(membase, SZ_1G - SZ_64M,
+                                 __dtb_fsl_ls1021a_iot_start);
+       }
+
+       arm_cpu_lowlevel_init();
+       ls102xa_init_lowlevel();
+
+       debug_ll_init();
+
+       udelay(500);
+       putc_ll('>');
+
+       IMD_USED_OF(fsl_ls1021a_iot);
+
+       fsl_ddr_set_memctl_regs(&ddrc[0], 0);
+
+       ls102xa_errata_post_ddr();
+
+       ls1021a_xload_start_image(SZ_1G, 0, 0);
+
+       pr_err("Booting failed\n");
+
+       while (1)
+               ;
+}
+
+void ls1021aiot_entry(unsigned long r0, unsigned long r1, unsigned long r2);
+
+__noreturn void
+ls1021aiot_entry(unsigned long r0, unsigned long r1, unsigned long r2)
+{
+       relocate_to_current_adr();
+       setup_c();
+
+       ls1021aiot_r_entry();
+}
diff --git a/arch/arm/boards/ls1021aiot/ls102xa_pbi.cfg 
b/arch/arm/boards/ls1021aiot/ls102xa_pbi.cfg
new file mode 100644
index 0000000000..840299be8d
--- /dev/null
+++ b/arch/arm/boards/ls1021aiot/ls102xa_pbi.cfg
@@ -0,0 +1,11 @@
+#PBI commands
+
+09570200 ffffffff
+09570158 00000300
+8940007c 21f47300
+#Configure Scratch register
+09ee0200 10000000
+#Configure alternate space
+09570158 00001000
+#Flush PBL data
+096100c0 000FFFFF
diff --git a/arch/arm/boards/ls1021aiot/ls102xa_rcw_sd_qspi.cfg 
b/arch/arm/boards/ls1021aiot/ls102xa_rcw_sd_qspi.cfg
new file mode 100644
index 0000000000..3b5300501d
--- /dev/null
+++ b/arch/arm/boards/ls1021aiot/ls102xa_rcw_sd_qspi.cfg
@@ -0,0 +1,8 @@
+#PBL preamble and RCW header
+aa55aa55 01ee0100
+
+#disable IFC, enable QSPI and DSPI
+0608000a 00000000 00000000 00000000
+20000000 08407900 e0025a00 21046000
+00000000 00000000 00000000 20038000
+20024800 881b1340 00000000 00000000
diff --git a/arch/arm/boards/ls1021aiot/start.S 
b/arch/arm/boards/ls1021aiot/start.S
new file mode 100644
index 0000000000..79cdc357c8
--- /dev/null
+++ b/arch/arm/boards/ls1021aiot/start.S
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include <linux/linkage.h>
+#include <asm/barebox-arm64.h>
+
+#define STACK_TOP 0x10020000
+
+ENTRY_PROC(start_ls1021aiot)
+    ldr r3, =STACK_TOP
+       mov sp, r3
+       b ls1021aiot_entry
+ENTRY_PROC_END(start_ls1021aiot)
diff --git a/arch/arm/configs/layerscape_v7_defconfig 
b/arch/arm/configs/layerscape_v7_defconfig
new file mode 100644
index 0000000000..208c61933e
--- /dev/null
+++ b/arch/arm/configs/layerscape_v7_defconfig
@@ -0,0 +1,100 @@
+CONFIG_ARCH_LS102XA=y
+CONFIG_MACH_LS1021AIOT=y
+CONFIG_MMU=y
+CONFIG_MALLOC_SIZE=0x0
+CONFIG_MALLOC_TLSF=y
+CONFIG_KALLSYMS=y
+CONFIG_RELOCATABLE=y
+CONFIG_HUSH_FANCY_PROMPT=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+CONFIG_MENU=y
+CONFIG_BOOTM_SHOW_TYPE=y
+CONFIG_BOOTM_VERBOSE=y
+CONFIG_BOOTM_INITRD=y
+CONFIG_BOOTM_OFTREE=y
+CONFIG_BOOTM_OFTREE_UIMAGE=y
+CONFIG_BLSPEC=y
+CONFIG_CONSOLE_ACTIVATE_NONE=y
+CONFIG_CONSOLE_ALLOW_COLOR=y
+CONFIG_PBL_CONSOLE=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_RESET_SOURCE=y
+CONFIG_CMD_DMESG=y
+CONFIG_LONGHELP=y
+CONFIG_CMD_IOMEM=y
+CONFIG_CMD_IMD=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_GO=y
+CONFIG_CMD_RESET=y
+CONFIG_CMD_UIMAGE=y
+CONFIG_CMD_PARTITION=y
+CONFIG_CMD_MOUNT=y
+CONFIG_CMD_UBI=y
+CONFIG_CMD_UBIFORMAT=y
+CONFIG_CMD_UMOUNT=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_LOADENV=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_MAGICVAR=y
+CONFIG_CMD_MAGICVAR_HELP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_FILETYPE=y
+CONFIG_CMD_LN=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_UNCOMPRESS=y
+CONFIG_CMD_LET=y
+CONFIG_CMD_MSLEEP=y
+CONFIG_CMD_READF=y
+CONFIG_CMD_SLEEP=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_TFTP=y
+CONFIG_CMD_MIITOOL=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_MENU=y
+CONFIG_CMD_MENU_MANAGEMENT=y
+CONFIG_CMD_MENUTREE=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_CRC=y
+CONFIG_CMD_CRC_CMP=y
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_MM=y
+CONFIG_CMD_CLK=y
+CONFIG_CMD_DETECT=y
+CONFIG_CMD_FLASH=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_LED=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_LED_TRIGGER=y
+CONFIG_CMD_BAREBOX_UPDATE=y
+CONFIG_CMD_OF_NODE=y
+CONFIG_CMD_OF_PROPERTY=y
+CONFIG_CMD_OFTREE=y
+CONFIG_CMD_TIME=y
+CONFIG_NET=y
+CONFIG_DRIVER_NET_GIANFAR=y
+CONFIG_OF_BAREBOX_DRIVERS=y
+CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_DRIVER_SPI_FSL_QUADSPI=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_I2C=y
+CONFIG_I2C_IMX=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_MUX_PCA954x=y
+CONFIG_MTD=y
+CONFIG_MTD_M25P80=y
+CONFIG_MCI=y
+CONFIG_MCI_MMC_BOOT_PARTITIONS=y
+CONFIG_MCI_IMX_ESDHC=y
+CONFIG_LED_PCA955X=y
+CONFIG_EEPROM_AT25=y
+CONFIG_EEPROM_AT24=y
+CONFIG_GPIO_PCA953X=y
+CONFIG_ZLIB=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_FS_TFTP=y
diff --git a/arch/arm/dts/fsl-ls1021a-iot.dts b/arch/arm/dts/fsl-ls1021a-iot.dts
new file mode 100644
index 0000000000..5d50829313
--- /dev/null
+++ b/arch/arm/dts/fsl-ls1021a-iot.dts
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Freescale ls1021a IOT board device tree source
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ */
+
+/dts-v1/;
+
+#include <arm/ls1021a-iot.dts>
+
+/ {
+       model = "LS1021A IOT Board";
+
+       aliases {
+               enet2-rgmii-phy = &rgmii_phy1;
+               enet0-sgmii-phy = &sgmii_phy2;
+               enet1-sgmii-phy = &sgmii_phy0;
+       };
+
+       chosen {
+               stdout-path = &uart0;
+
+               environment {
+                       compatible = "barebox,environment";
+                       device-path = &environment_qspi;
+               };
+       };
+};
+
+&qspi {
+       bus-num = <0>;
+       status = "okay";
+
+       s70fl01gs: flash@0 {
+               compatible = "jedec,spi-nor";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               spi-max-frequency = <20000000>;
+               reg = <0>;
+
+               partitions {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       compatible = "fixed-partitions";
+
+                       partition@0 {
+                               label = "barebox";
+                               reg = <0 0x100000>;
+                       };
+
+                       environment_qspi: partition@100000 {
+                               label = "barebox-environment";
+                               reg = <0x100000 0x40000>;
+                       };
+               };
+       };
+};
+
+&i2c0 {
+       status = "disabled";
+};
+
+&i2c1 {
+       status = "okay";
+       eeprom@51 {
+               compatible = "atmel,24c512";
+               reg = <0x51>;
+       };
+};
+
+/* I2C1 and I2C1 are connected due to Errata on rev1 board */
+&i2c2 {
+       status = "disabled";
+};
+
+&enet0 {
+       phy-handle = <&sgmii_phy2>;
+       phy-mode = "sgmii";
+       status = "disabled";
+};
+
+&enet1 {
+       tbi-handle = <&tbi0>;
+       phy-handle = <&sgmii_phy0>;
+       phy-mode = "sgmii";
+       status = "okay";
+};
+
+&enet2 {
+       phy-handle = <&rgmii_phy1>;
+       phy-connection-type = "rgmii-id";
+       status = "disabled";
+};
+
+&mdio0 {
+       sgmii_phy0: ethernet-phy@3 {
+               reg = <0x3>;
+       };
+       rgmii_phy1: ethernet-phy@1 {
+               reg = <0x1>;
+       };
+       sgmii_phy2: ethernet-phy@2 {
+               reg = <0x2>;
+       };
+       tbi0: tbi-phy@1f {
+               reg = <0x1f>;
+               device_type = "tbi-phy";
+       };
+};
+
+&mdio1 {
+       status = "disabled";
+};
+
+&uart0 {
+       status = "okay";
+       clock-frequency = <150000000>;
+};
+
+&uart1 {
+       status = "disabled";
+};
diff --git a/arch/arm/lib32/Makefile b/arch/arm/lib32/Makefile
index 82507fffc0..1be8d70c45 100644
--- a/arch/arm/lib32/Makefile
+++ b/arch/arm/lib32/Makefile
@@ -31,6 +31,7 @@ extra-y += barebox.lds
 pbl-y  += lib1funcs.o
 pbl-y  += ashldi3.o
 pbl-y  += div0.o
+pbl-y  += pbl.o
 
 obj-pbl-y      += setjmp.o
 
diff --git a/arch/arm/lib32/pbl.c b/arch/arm/lib32/pbl.c
new file mode 100644
index 0000000000..f4be7b57dc
--- /dev/null
+++ b/arch/arm/lib32/pbl.c
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <asm/system.h>
+#include <clock.h>
+#include <common.h>
+
+void udelay(unsigned long us)
+{
+       unsigned long long ticks, cntfrq = get_cntfrq();
+       unsigned long long start = get_cntpct();
+
+       ticks = us * cntfrq + 999999;
+       do_div(ticks, 1000000);
+
+       while ((long)(start + ticks - get_cntpct()) > 0);
+}
+
+void mdelay(unsigned long ms)
+{
+       udelay(ms * 1000);
+}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 30de1f544c..19709b0163 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -189,7 +189,7 @@ config DRIVER_NET_FSL_FMAN
 
 config DRIVER_NET_GIANFAR
        bool "Gianfar Ethernet"
-       depends on ARCH_MPC85XX
+       depends on ARCH_MPC85XX || ARCH_LS102XA
        select PHYLIB
 
 config DRIVER_NET_KS8851_MLL
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 4b374b4a50..d7ecd8f6c6 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -16,6 +16,7 @@
 #include <driver.h>
 #include <command.h>
 #include <errno.h>
+#include <of_address.h>
 #include <asm/io.h>
 #include <linux/phy.h>
 #include <linux/err.h>
@@ -26,6 +27,19 @@
 #define RX_BUF_CNT     PKTBUFSRX
 #define BUF_ALIGN      8
 
+#define TBIANA_SETTINGS ( \
+       GFAR_TBIANA_ASYMMETRIC_PAUSE \
+       | GFAR_TBIANA_SYMMETRIC_PAUSE \
+       | GFAR_TBIANA_FULL_DUPLEX \
+       )
+
+#define TSEC_TBICR_SETTINGS ( \
+       GFAR_TBICR_PHY_RESET \
+       | GFAR_TBICR_ANEG_ENABLE \
+       | GFAR_TBICR_FULL_DUPLEX \
+       | GFAR_TBICR_SPEED1_SET \
+       )
+
 /*
  * Initialize required registers to appropriate values, zeroing
  * those we don't care about (unless zero is bad, in which case,
@@ -82,11 +96,12 @@ static void gfar_adjust_link(struct eth_device *edev)
        u32 ecntrl, maccfg2;
 
        priv->link = edev->phydev->link;
-       priv->duplexity =edev->phydev->duplex;
+       priv->duplexity = edev->phydev->duplex;
+       priv->speed = edev->phydev->speed;
 
        if (edev->phydev->speed == SPEED_1000)
                priv->speed = 1000;
-       if (edev->phydev->speed == SPEED_100)
+       else if (edev->phydev->speed == SPEED_100)
                priv->speed = 100;
        else
                priv->speed = 10;
@@ -126,11 +141,11 @@ static void gfar_adjust_link(struct eth_device *edev)
                out_be32(regs + GFAR_ECNTRL_OFFSET, ecntrl);
                out_be32(regs + GFAR_MACCFG2_OFFSET, maccfg2);
 
-               dev_info(&edev->dev, "Speed: %d, %s duplex\n", priv->speed,
-                      (priv->duplexity) ? "full" : "half");
+               dev_dbg(&edev->dev, "Speed: %d, %s duplex\n", priv->speed,
+                       (priv->duplexity) ? "full" : "half");
 
        } else {
-               dev_info(&edev->dev, "No link.\n");
+               dev_dbg(&edev->dev, "No link.\n");
        }
 }
 
@@ -187,7 +202,7 @@ static int gfar_open(struct eth_device *edev)
        int ret;
 
        ret = phy_device_connect(edev, &phy->miibus, priv->phyaddr,
-                                gfar_adjust_link, 0, PHY_INTERFACE_MODE_NA);
+                                gfar_adjust_link, 0, phy->interface);
        if (ret)
                return ret;
 
@@ -246,7 +261,10 @@ static int gfar_set_ethaddr(struct eth_device *edev, const 
unsigned char *mac)
 
        out_be32(regs + GFAR_MACSTRADDR1_OFFSET, tempval);
 
-       tempval = *((uint *)(tmpbuf + 4));
+       if (IS_ENABLED(CONFIG_PPC))
+               tempval = *((uint *)(tmpbuf + 4));
+       else
+               tempval = tmpbuf[4] << 24 | tmpbuf[5] << 16;
 
        out_be32(regs + GFAR_MACSTRADDR2_OFFSET, tempval);
 
@@ -342,26 +360,33 @@ static void gfar_init_phy(struct eth_device *dev)
        struct gfar_phy *phy = priv->gfar_mdio;
        void __iomem *regs = priv->regs;
        uint64_t start;
+       uint32_t ecntrl;
+
 
        gfar_local_mdio_write(phy->regs, priv->phyaddr, GFAR_MIIM_CR,
-                       GFAR_MIIM_CR_RST);
+               GFAR_MIIM_CR_RST);
 
        start = get_time_ns();
        while (!is_timeout(start, 10 * MSECOND)) {
                if (!(gfar_local_mdio_read(phy->regs, priv->phyaddr,
-                                       GFAR_MIIM_CR) & GFAR_MIIM_CR_RST))
+                               GFAR_MIIM_CR) & GFAR_MIIM_CR_RST))
                        break;
        }
 
-       if (in_be32(regs + GFAR_ECNTRL_OFFSET) & GFAR_ECNTRL_SGMII_MODE)
+       ecntrl = in_be32(regs + GFAR_ECNTRL_OFFSET);
+       if (ecntrl & GFAR_ECNTRL_SGMII_MODE) {
+               phy->interface = PHY_INTERFACE_MODE_SGMII;
                gfar_configure_serdes(priv);
+       } else if (ecntrl & ECNTRL_REDUCED_MODE) {
+               phy->interface = PHY_INTERFACE_MODE_RGMII;
+       }
 }
 
 static int gfar_send(struct eth_device *edev, void *packet, int length)
 {
        struct gfar_private *priv = edev->priv;
        void __iomem *regs = priv->regs;
-       struct device *dev = edev->parent;
+       struct device_d *dev = edev->parent;
        uint64_t start;
        uint tidx;
        uint16_t status;
@@ -401,7 +426,7 @@ static int gfar_send(struct eth_device *edev, void *packet, 
int length)
 static int gfar_recv(struct eth_device *edev)
 {
        struct gfar_private *priv = edev->priv;
-       struct device *dev = edev->parent;
+       struct device_d *dev = edev->parent;
        void __iomem *regs = priv->regs;
        uint16_t status, length;
 
@@ -409,7 +434,6 @@ static int gfar_recv(struct eth_device *edev)
                return 0;
 
        length = in_be16(&priv->rxbd[priv->rxidx].length);
-
        /* Send the packet up if there were no errors */
        status = in_be16(&priv->rxbd[priv->rxidx].status);
        if (!(status & RXBD_STATS))
@@ -464,16 +488,135 @@ static int gfar_miiphy_write(struct mii_bus *bus, int 
addr, int reg,
        return 0;
 }
 
+#ifdef CONFIG_OFDEVICE
+static int gfar_probe(struct device_d *dev)
+{
+       struct eth_device *edev;
+       struct gfar_private *priv;
+       struct device_node *np;
+       uint32_t tbiaddr = 0x1f;
+       size_t size;
+       char *p;
+
+       priv = xzalloc(sizeof(struct gfar_private));
+
+       edev = &priv->edev;
+
+       priv->regs = dev_get_mem_region(dev, 0);
+       if (IS_ERR(priv->regs)) {
+               struct device_node *child;
+
+               child = of_get_next_child(dev->device_node, NULL);
+               for_each_child_of_node(dev->device_node, child) {
+                       if (child->name && !strncmp(child->name, "queue-group",
+                                               strlen("queue-group"))) {
+                               priv->regs = of_iomap(child, 0);
+                               if (IS_ERR(priv->regs)) {
+                                       pr_err("Failed to acquire first group 
address\n");
+                                       return PTR_ERR(priv->regs);
+                               }
+                               break;
+                       }
+               }
+       }
+
+       priv->phyaddr = -1;
+       np = of_parse_phandle_from(dev->device_node, NULL, "phy-handle", 0);
+       if (np) {
+               struct device_node *parent;
+               uint32_t reg = 0;
+
+               /* Get mdio parent */
+               parent = of_get_parent(np);
+               if (!parent)  {
+                       pr_err("No parent node for phy-handle\n");
+                       return PTR_ERR(parent);
+               }
+               priv->gfar_mdio = parent->dev->priv;
+               if (!of_property_read_u32(np, "reg", &reg))
+                       priv->phyaddr = reg;
+       } else {
+               pr_err("Could not get phy-handle address\n");
+               return -ENOENT;
+       }
+
+       priv->tbicr = TSEC_TBICR_SETTINGS;
+       priv->tbiana = TBIANA_SETTINGS;
+
+       /* Handle to tbi node */
+       np = of_parse_phandle_from(dev->device_node, NULL, "tbi-handle", 0);
+       if (np) {
+               struct gfar_phy *tbiphy;
+               struct device_node *parent;
+
+               /* Get tbi address to be programmed in device */
+               if (of_property_read_u32(np, "reg", &tbiaddr)) {
+                       pr_err("Failed to get tbi reg property\n");
+                       return -ENOENT;
+               }
+               /* mdio is the parent  */
+               parent = of_get_parent(np);
+               if (!parent)  {
+                       pr_err("No parent node for TBI PHY?\n");
+                       return -ENOENT;
+               }
+               tbiphy = xzalloc(sizeof(*tbiphy));
+               tbiphy->dev = parent->dev;
+               tbiphy->regs = dev_get_mem_region(tbiphy->dev, 0);
+
+               if (IS_ERR(tbiphy->regs)) {
+                       pr_err("Could not get TBI address\n");
+                       free(tbiphy);
+                       return PTR_ERR(tbiphy->regs);
+               }
+
+               tbiphy->miibus.read = gfar_miiphy_read;
+               tbiphy->miibus.write = gfar_miiphy_write;
+               tbiphy->miibus.priv = tbiphy;
+               tbiphy->miibus.parent = dev;
+               tbiphy->dev->priv = tbiphy;
+               priv->gfar_tbi = tbiphy;
+       }
+
+       priv->tbiaddr = tbiaddr;
+       out_be32(priv->regs + GFAR_TBIPA_OFFSET, priv->tbiaddr);
+
+       size = ((TX_BUF_CNT * sizeof(struct txbd8)) +
+               (RX_BUF_CNT * sizeof(struct rxbd8))) + BUF_ALIGN;
+       p = (char *)xmemalign(BUF_ALIGN, size);
+       priv->txbd = (struct txbd8 __iomem *)p;
+       priv->rxbd = (struct rxbd8 __iomem *)(p +
+                       (TX_BUF_CNT * sizeof(struct txbd8)));
+
+       edev->priv = priv;
+       edev->init = gfar_init;
+       edev->open = gfar_open;
+       edev->halt = gfar_halt;
+       edev->send = gfar_send;
+       edev->recv = gfar_recv;
+       edev->get_ethaddr = gfar_get_ethaddr;
+       edev->set_ethaddr = gfar_set_ethaddr;
+       edev->parent = dev;
+
+       setbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
+       udelay(2);
+       clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
+
+       gfar_init_phy(edev);
+
+       return eth_register(edev);
+}
+#else
 /*
  * Initialize device structure. Returns success if
  * initialization succeeded.
  */
-static int gfar_probe(struct device *dev)
+static int gfar_probe(struct device_d *dev)
 {
        struct gfar_info_struct *gfar_info = dev->platform_data;
        struct eth_device *edev;
        struct gfar_private *priv;
-       struct device *mdev;
+       struct device_d *mdev;
        size_t size;
        char devname[16];
        char *p;
@@ -535,21 +678,41 @@ static int gfar_probe(struct device *dev)
 
        return eth_register(edev);
 }
+#endif
 
-static struct driver gfar_eth_driver = {
+static const struct of_device_id gfar_ids[] = {
+       { .compatible = "fsl,etsec2" },
+       { .compatible = "gianfar" },
+};
+
+static struct driver_d gfar_eth_driver = {
        .name  = "gfar",
+#ifdef CONFIG_OFDEVICE
+       .of_compatible = DRV_OF_COMPAT(gfar_ids),
+#endif
        .probe = gfar_probe,
 };
 device_platform_driver(gfar_eth_driver);
 
-static int gfar_phy_probe(struct device *dev)
+/* MII bus */
+static struct fsl_pq_mdio_data mdio_gianfar_data = {
+       .mdio_regs_off = 0x0,
+};
+
+static const struct of_device_id gfar_mdio_ids[] = {
+       { .compatible = "gianfar", .data = &mdio_gianfar_data },
+};
+
+static int gfar_phy_probe(struct device_d *dev)
 {
        struct gfar_phy *phy;
+       struct fsl_pq_mdio_data *data;
        int ret;
 
+       data = (struct fsl_pq_mdio_data *)device_get_match_data(dev);
        phy = xzalloc(sizeof(*phy));
        phy->dev = dev;
-       phy->regs = dev_get_mem_region(dev, 0);
+       phy->regs = dev_get_mem_region(dev, 0) + data->mdio_regs_off;
        if (IS_ERR(phy->regs))
                return PTR_ERR(phy->regs);
 
@@ -567,13 +730,18 @@ static int gfar_phy_probe(struct device *dev)
        return 0;
 }
 
-static struct driver gfar_phy_driver = {
+static struct driver_d gfar_phy_driver = {
        .name  = "gfar-mdio",
+#ifdef CONFIG_OFDEVICE
+       .of_compatible = DRV_OF_COMPAT(gfar_mdio_ids),
+#endif
        .probe = gfar_phy_probe,
 };
 register_driver_macro(coredevice, platform, gfar_phy_driver);
 
-static int gfar_tbiphy_probe(struct device *dev)
+#ifndef CONFIG_OFDEVICE
+
+static int gfar_tbiphy_probe(struct device_d *dev)
 {
        struct gfar_phy *phy;
        int ret;
@@ -597,8 +765,9 @@ static int gfar_tbiphy_probe(struct device *dev)
        return 0;
 }
 
-static struct driver gfar_tbiphy_driver = {
+static struct driver_d gfar_tbiphy_driver = {
        .name  = "gfar-tbiphy",
        .probe = gfar_tbiphy_probe,
 };
 register_driver_macro(coredevice, platform, gfar_tbiphy_driver);
+#endif
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index cea41218a7..451fa17706 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -15,7 +15,9 @@
 
 #include <net.h>
 #include <config.h>
+#ifdef CONFIG_ARCH_MPC85XX
 #include <mach/gianfar.h>
+#endif
 
 #define MAC_ADDR_LEN 6
 
@@ -27,6 +29,10 @@
 #define GFAR_TBI_ANEX          0x06
 #define GFAR_TBI_TBICON                0x11
 
+#ifndef GFAR_TBIPA_OFFSET
+#define GFAR_TBIPA_OFFSET       0x030
+#endif
+
 /* TBI MDIO register bit fields*/
 #define GFAR_TBICON_CLK_SELECT         0x0020
 #define GFAR_TBIANA_ASYMMETRIC_PAUSE   0x0100
@@ -64,7 +70,9 @@
 
 #define ECNTRL_INIT_SETTINGS           0x00001000
 #define GFAR_ECNTRL_TBI_MODE           0x00000020
+#define ECNTRL_REDUCED_MODE            0x00000010
 #define GFAR_ECNTRL_R100               0x00000008
+#define GFAR_ECNTRL_RMM                        0x00000004
 #define GFAR_ECNTRL_SGMII_MODE         0x00000002
 
 #ifndef GFAR_TBIPA_VALUE
@@ -261,7 +269,8 @@ struct rxbd8 {
 
 struct gfar_phy {
        void __iomem *regs;
-       struct device *dev;
+       struct device_d *dev;
+       phy_interface_t interface;
        struct mii_bus miibus;
 };
 
@@ -279,8 +288,13 @@ struct gfar_private {
        uint phyaddr;
        uint tbicr;
        uint tbiana;
+       uint tbiaddr;
        uint link;
        uint duplexity;
        uint speed;
 };
+
+struct fsl_pq_mdio_data {
+       uint32_t mdio_regs_off;
+};
 #endif /* __GIANFAR_H */



Reply via email to