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@xxxxxxxxx> --- 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@xxxxxxxxx>, + +#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@xxxxxxxxx> + +/* + * 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", ®)) + 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 */