[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", ®))
+ 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