[PATCH 2/2] ARM: Layerscape: Add LS1021A IOT board support

Renaud Barbier Renaud.Barbier at ametek.com
Wed Feb 8 05:26:30 PST 2023


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 <renaud.barbier at abaco.com>
---
 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 <renaud.barbier at abaco.com>,
+
+#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 <renaud.barbier at abaco.com>
+
+/*
+ * 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 at 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 at 0 {
+				label = "barebox";
+				reg = <0 0x100000>;
+			};
+
+			environment_qspi: partition at 100000 {
+				label = "barebox-environment";
+				reg = <0x100000 0x40000>;
+			};
+		};
+	};
+};
+
+&i2c0 {
+	status = "disabled";
+};
+
+&i2c1 {
+	status = "okay";
+	eeprom at 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 at 3 {
+		reg = <0x3>;
+	};
+	rgmii_phy1: ethernet-phy at 1 {
+		reg = <0x1>;
+	};
+	sgmii_phy2: ethernet-phy at 2 {
+		reg = <0x2>;
+	};
+	tbi0: tbi-phy at 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 */




More information about the barebox mailing list