imx6: drop 4.1 support

Signed-off-by: Luka Perkov <luka@openwrt.org>

SVN-Revision: 48300
This commit is contained in:
Luka Perkov 2016-01-18 06:43:50 +00:00
parent c4de2dfd2d
commit cdfeab0931
13 changed files with 0 additions and 2862 deletions

View File

@ -1,383 +0,0 @@
CONFIG_AHCI_IMX=y
CONFIG_ALIGNMENT_TRAP=y
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
CONFIG_ARCH_HAS_SG_CHAIN=y
CONFIG_ARCH_HAS_TICK_BROADCAST=y
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_MULTIPLATFORM=y
# CONFIG_ARCH_MULTI_CPU_AUTO is not set
CONFIG_ARCH_MULTI_V6_V7=y
CONFIG_ARCH_MULTI_V7=y
CONFIG_ARCH_MXC=y
CONFIG_ARCH_NR_GPIO=0
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARM=y
# CONFIG_ARM_CPU_SUSPEND is not set
CONFIG_ARM_ERRATA_754322=y
CONFIG_ARM_ERRATA_764369=y
CONFIG_ARM_ERRATA_775420=y
CONFIG_ARM_GIC=y
CONFIG_ARM_HAS_SG_CHAIN=y
CONFIG_ARM_IMX6Q_CPUFREQ=y
CONFIG_ARM_L1_CACHE_SHIFT=6
CONFIG_ARM_L1_CACHE_SHIFT_6=y
# CONFIG_ARM_LPAE is not set
CONFIG_ARM_PATCH_PHYS_VIRT=y
CONFIG_ARM_THUMB=y
# CONFIG_ARM_THUMBEE is not set
CONFIG_ARM_VIRT_EXT=y
CONFIG_ATA=y
CONFIG_ATAGS=y
# CONFIG_ATA_SFF is not set
CONFIG_AUTO_ZRELADDR=y
CONFIG_CACHE_L2X0=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLKSRC_MMIO=y
CONFIG_CLKSRC_OF=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_COMMON_CLK=y
CONFIG_CPUFREQ_DT=y
CONFIG_CPU_32v6K=y
CONFIG_CPU_32v7=y
CONFIG_CPU_ABRT_EV7=y
# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_CPU_CACHE_V7=y
CONFIG_CPU_CACHE_VIPT=y
CONFIG_CPU_COPY_V6=y
CONFIG_CPU_CP15=y
CONFIG_CPU_CP15_MMU=y
CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
CONFIG_CPU_FREQ_GOV_COMMON=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_FREQ_STAT_DETAILS=y
CONFIG_CPU_HAS_ASID=y
# CONFIG_CPU_ICACHE_DISABLE is not set
CONFIG_CPU_PABRT_V7=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_TLB_V7=y
CONFIG_CPU_V7=y
CONFIG_CRC16=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_LZO=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CRYPTO_XZ=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_IMX_UART_PORT=1
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
# CONFIG_DEBUG_UART_8250 is not set
# CONFIG_DEBUG_USER is not set
CONFIG_DECOMPRESS_BZIP2=y
CONFIG_DECOMPRESS_GZIP=y
CONFIG_DECOMPRESS_LZO=y
CONFIG_DECOMPRESS_XZ=y
CONFIG_DMADEVICES=y
CONFIG_DMA_ENGINE=y
CONFIG_DMA_OF=y
CONFIG_DTC=y
# CONFIG_DW_DMAC_PCI is not set
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_FEC=y
CONFIG_FRAME_POINTER=y
# CONFIG_FSL_PQ_MDIO is not set
CONFIG_FS_MBCACHE=y
CONFIG_FS_POSIX_ACL=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GLOB=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_DEVRES=y
CONFIG_GPIO_GENERIC=y
CONFIG_GPIO_MXC=y
CONFIG_GPIO_SYSFS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
CONFIG_HAVE_ARCH_BITREVERSE=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_PFN_VALID=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_ARM_SCU=y
CONFIG_HAVE_ARM_TWD=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_BPF_JIT=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_HW_BREAKPOINT=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IMX_ANATOP=y
CONFIG_HAVE_IMX_GPC=y
CONFIG_HAVE_IMX_MMDC=y
CONFIG_HAVE_IMX_SRC=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_LZ4=y
CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_HAVE_KERNEL_XZ=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_OPTPROBES=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_PERF_REGS=y
CONFIG_HAVE_PERF_USER_STACK_DUMP=y
CONFIG_HAVE_PROC_CPU=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SMP=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_UID16=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
# CONFIG_HSU_DMA_PCI is not set
CONFIG_HZ_FIXED=0
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_IMX=y
CONFIG_IMX2_WDT=y
CONFIG_IMX_DMA=y
CONFIG_IMX_SDMA=y
# CONFIG_IMX_WEIM is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IOMMU_HELPER=y
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=y
CONFIG_JBD=y
CONFIG_JBD2=y
CONFIG_LIBFDT=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MDIO_BOARDINFO=y
CONFIG_MFD_SYSCON=y
CONFIG_MICREL_PHY=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_MIGHT_HAVE_PCI=y
CONFIG_MMC=y
CONFIG_MMC_BLOCK=y
# CONFIG_MMC_MXC is not set
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ESDHC_IMX=y
CONFIG_MMC_SDHCI_IO_ACCESSORS=y
# CONFIG_MMC_SDHCI_PCI is not set
CONFIG_MMC_SDHCI_PLTFM=y
# CONFIG_MMC_TIFM_SD is not set
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_NAND_GPMI_NAND=y
# CONFIG_MTD_PHYSMAP_OF is not set
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
CONFIG_MTD_UBI_BLOCK=y
# CONFIG_MTD_UBI_FASTMAP is not set
# CONFIG_MTD_UBI_GLUEBI is not set
CONFIG_MTD_UBI_WL_THRESHOLD=4096
CONFIG_MULTI_IRQ_HANDLER=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
# CONFIG_MX3_IPU is not set
CONFIG_MXS_DMA=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEON=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_PTP_CLASSIFY=y
CONFIG_NLS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NO_BOOTMEM=y
CONFIG_NO_HZ_COMMON=y
CONFIG_NO_HZ_IDLE=y
CONFIG_NR_CPUS=4
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_ADDRESS_PCI=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_MTD=y
CONFIG_OF_NET=y
CONFIG_OF_PCI=y
CONFIG_OF_PCI_IRQ=y
CONFIG_OF_RESERVED_MEM=y
CONFIG_OLD_SIGACTION=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_OUTER_CACHE=y
CONFIG_OUTER_CACHE_SYNC=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0x80000000
CONFIG_PCI=y
CONFIG_PCIEAER=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCIE_DW=y
# CONFIG_PCIE_IPROC is not set
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_DOMAINS_GENERIC=y
CONFIG_PCI_IMX6=y
CONFIG_PERF_EVENTS=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_IMX=y
CONFIG_PINCTRL_IMX6Q=y
CONFIG_PINCTRL_IMX6SL=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_PL310_ERRATA_588369=y
CONFIG_PL310_ERRATA_727915=y
# CONFIG_PL310_ERRATA_753970 is not set
CONFIG_PL310_ERRATA_769419=y
CONFIG_PM_OPP=y
CONFIG_PPS=y
CONFIG_PTP_1588_CLOCK=y
CONFIG_RAS=y
CONFIG_RATIONAL=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_RD_BZIP2=y
CONFIG_RD_GZIP=y
CONFIG_RD_LZO=y
CONFIG_RD_XZ=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MMIO=y
CONFIG_REGMAP_SPI=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_ANATOP=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_PFUZE100=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
CONFIG_RTC_CLASS=y
# CONFIG_RTC_DRV_IMXDI is not set
# CONFIG_RTC_DRV_MXC is not set
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_SCHED_HRTICK=y
CONFIG_SCSI=y
CONFIG_SERIAL_IMX=y
CONFIG_SERIAL_IMX_CONSOLE=y
CONFIG_SMP=y
CONFIG_SMP_ON_UP=y
CONFIG_SOC_BUS=y
# CONFIG_SOC_IMX50 is not set
# CONFIG_SOC_IMX51 is not set
# CONFIG_SOC_IMX53 is not set
CONFIG_SOC_IMX6=y
CONFIG_SOC_IMX6Q=y
CONFIG_SOC_IMX6SL=y
# CONFIG_SOC_IMX6SX is not set
# CONFIG_SOC_LS1021A is not set
# CONFIG_SOC_VF610 is not set
CONFIG_SPARSE_IRQ=y
CONFIG_SPI=y
CONFIG_SPI_BITBANG=y
CONFIG_SPI_IMX=y
CONFIG_SPI_MASTER=y
CONFIG_SRAM=y
CONFIG_SRCU=y
CONFIG_STMP_DEVICE=y
CONFIG_STOP_MACHINE=y
CONFIG_SWIOTLB=y
CONFIG_SWP_EMULATE=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
# CONFIG_THUMB2_KERNEL is not set
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TREE_RCU=y
CONFIG_UBIFS_FS=y
CONFIG_UBIFS_FS_ADVANCED_COMPR=y
CONFIG_UBIFS_FS_LZO=y
CONFIG_UBIFS_FS_XZ=y
CONFIG_UBIFS_FS_ZLIB=y
CONFIG_UID16=y
CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
# CONFIG_USB_MXS_PHY is not set
CONFIG_USB_SUPPORT=y
CONFIG_USE_OF=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_VFP=y
CONFIG_VFPv3=y
CONFIG_VMSPLIT_2G=y
# CONFIG_VMSPLIT_3G is not set
CONFIG_WATCHDOG_CORE=y
CONFIG_XPS=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_BCJ=y
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZONE_DMA_FLAG=0

View File

@ -1,950 +0,0 @@
/*
* drivers/net/phy/gw16083.c
*
* Driver for GW16083 Ventana Ethernet Expansion Mezzanine
*
* Author: Tim Harvey
*
* Copyright (c) 2014 Tim Harvey <tharvey@gateworks.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
/*
* The GW16083 interfaces with a Ventana baseboard via the PCIe bus, an i2c
* bus (i2c2), and a couple of GPIO's. On the PCIe bus is an i210 GigE with
* its MAC connected to Port4 of a Marvell MV88E6176 7-port GigE switch via
* MDIO and RGMII. Ports 0-3 are standard copper RJ45 but Ports 5 and 6
* connect to Marvell MV88E1111 dual-mode Copper/Fiber PHY's over SGMII and
* MDIO. The PHY's have both an RG45 for copper and an SFP module.
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/marvell_phy.h>
#include <linux/of_platform.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <linux/uaccess.h>
#include "gw16083.h"
#undef FAIL_ON_CHECKSUM_ERR /* fail to configure SFP if checksum bad */
#define PORT_POWER_CONTROL /* ports can be enabled/disabled via sysfs */
#define PORT_MODE_CONTROL /* ports 5/6 can have SFP/RJ45 mode forced */
MODULE_DESCRIPTION("GW16083 driver");
MODULE_AUTHOR("Tim Harvey");
MODULE_LICENSE("GPL");
struct mv88e1111_port_state {
int port;
bool present;
bool serdes;
bool sfp_signal;
bool sfp_present;
bool sfp_compat;
bool sfp_enabled;
char sfp_id[64];
};
struct mv88e1111_priv {
struct phy_device *phydev;
struct i2c_client *client;
struct mv88e1111_port_state port5;
struct mv88e1111_port_state port6;
struct kobject *sysfs_kobj;
};
enum {
mode_copper = 0,
mode_serdes = 1,
};
static struct i2c_client *gw16083_client = NULL;
static int gw16083_read_port_sfp(struct i2c_client *client,
struct mv88e1111_port_state *state);
/* read switch port register from port0-6 */
u16 read_switch_port(struct phy_device *pdev, int port, u8 regaddr)
{
return pdev->bus->read(pdev->bus, MV_BASE + port, regaddr);
}
/* write switch port register to port0-6 */
int write_switch_port(struct phy_device *pdev, int port, u8 regaddr, u16 val)
{
return pdev->bus->write(pdev->bus, MV_BASE + port, regaddr, val);
}
/*
* read_switch_port_phy - write a register for a specific port on 88E6176
* The 88E6176 PHY registers must be accessed thorugh the Global2 address
* using the SMI_PHY_COMMAND_REG and SMI_PHY_DATA_REG.
*/
int read_switch_port_phy(struct phy_device *pdev, int port, u8 regaddr)
{
u16 reg;
int i;
dev_dbg(&pdev->dev, "read_phy: port%d reg=0x%02x\n", port, regaddr);
reg = SMIBUSY | SMIMODE22 | SMIOP_READ;
reg |= port << DEVADDR;
reg |= regaddr << REGADDR;
pdev->bus->write(pdev->bus, MV_GLOBAL2, MV_SMI_PHY_COMMAND, reg);
for (i = 0; i < 10; i++) {
reg = pdev->bus->read(pdev->bus, MV_GLOBAL2,
MV_SMI_PHY_COMMAND);
if (!(reg & (1<<15)))
break;
mdelay(1);
}
/* timeout */
if (i == 10)
return 0xffff;
reg = pdev->bus->read(pdev->bus, MV_GLOBAL2, MV_SMI_PHY_DATA);
return reg;
}
/*
* write_switch_port_phy - write a register for a specific port on 88E6176
* The 88E6176 PHY registers must be accessed thorugh the Global2 address
* using the SMI_PHY_COMMAND_REG and SMI_PHY_DATA_REG.
*/
int write_switch_port_phy(struct phy_device *pdev, int port, u8 addr, u16 reg)
{
int i;
dev_dbg(&pdev->dev, "write_phy: port%d reg=0x%02x val=0x%04x\n", port,
addr, reg);
pdev->bus->write(pdev->bus, MV_GLOBAL2, MV_SMI_PHY_DATA, reg);
reg = SMIBUSY | SMIMODE22 | SMIOP_WRITE;
reg |= port << DEVADDR;
reg |= addr << REGADDR;
pdev->bus->write(pdev->bus, MV_GLOBAL2, MV_SMI_PHY_COMMAND, reg);
for (i = 0; i < 10; i++) {
reg = pdev->bus->read(pdev->bus, MV_GLOBAL2,
MV_SMI_PHY_COMMAND);
if (!(reg & (1<<15)))
break;
mdelay(1);
}
/* timeout */
if (i == 10)
return -ETIMEDOUT;
return 0;
}
/* read a scratch register from switch */
inline u8 read_switch_scratch(struct phy_device *pdev, u8 reg)
{
pdev->bus->write(pdev->bus, MV_GLOBAL2, MV_SCRATCH_MISC, (reg << 8));
return pdev->bus->read(pdev->bus, MV_GLOBAL2, MV_SCRATCH_MISC) & 0xff;
}
/* write a scratch register to switch */
inline void write_switch_scratch(struct phy_device *pdev, u8 reg, u8 val)
{
pdev->bus->write(pdev->bus, MV_GLOBAL2, MV_SCRATCH_MISC,
(1 << 15) | (reg << 8) | val);
}
/* enable or disable an SFP's TXEN signal */
static int enable_sfp_txen(struct phy_device *pdev, int port, bool enable)
{
u8 gpio;
int bit;
if (port != 5 && port != 6)
return -EINVAL;
/* GPIO[2:1] output low to enable TXEN */
bit = (port == 5) ? 1 : 2;
gpio = read_switch_scratch(pdev, MV_GPIO_DATA);
if (enable)
gpio |= (1 << bit);
else
gpio &= (1 << bit);
write_switch_scratch(pdev, MV_GPIO_DATA, gpio);
dev_info(&pdev->dev, "Port%d: SFP TX %s\n", port, enable ?
"enabled" : "disabled");
return 0;
}
/* configure mv88e1111 port for copper or serdes
* For Copper we set auto link/duplex/speed detection
* For SerDes/Fiber we force 1000mbps link up and auto-neg duplex
*/
static int config_mv88e1111_port_sfp(struct phy_device *pdev, int port,
bool sfp)
{
u16 reg;
if (port != 5 && port != 6)
return -EINVAL;
dev_dbg(&pdev->dev, "%s: Port%d %s\n", __func__, port,
sfp ? "SFP" : "copper");
if (sfp) {
enable_sfp_txen(pdev, port, 1);
/* configure MV88E6176 Physical Control Port Register */
dev_info(&pdev->dev,
"Port%d: SFP: force 1000mbps link up "
"(auto-negotiate duplex)\n",
port);
reg = read_switch_port(pdev, port, MV_PORT_PHYS_CONTROL);
reg &= ~0x3f; /* clear 5-0 */
reg |= (1 << 4) | (1 << 5); /* force link up */
reg |= 2; /* force 1000mbps */
write_switch_port(pdev, port, MV_PORT_PHYS_CONTROL, reg);
reg = read_switch_port(pdev, port, MV_PORT_PHYS_CONTROL);
}
/* copper */
else {
enable_sfp_txen(pdev, port, 0);
/* configure MV88E6176 Physical Control Port Register */
dev_info(&pdev->dev,
"Port%d: Copper: set auto-neg link/duplex/speed\n",
port);
reg = read_switch_port(pdev, port, MV_PORT_PHYS_CONTROL);
reg &= ~0x3f; /* clear 5-0 */
reg |= 3; /* speed not forced */
write_switch_port(pdev, port, MV_PORT_PHYS_CONTROL, reg);
reg = read_switch_port(pdev, port, MV_PORT_PHYS_CONTROL);
}
dev_dbg(&pdev->dev, "%s: Port%d %s PORT_PHYS_CONTROL=0x%04x\n",
__func__, port, sfp ? "SFP" : "copper",
read_switch_port(pdev, port, MV_PORT_PHYS_CONTROL));
return 0;
}
#if defined(PORT_POWER_CONTROL)
static int enable_switch_port(struct phy_device *pdev, int port, bool enable)
{
struct mv88e1111_priv *priv = dev_get_drvdata(&pdev->dev);
u16 reg;
/* power up port */
dev_info(&priv->client->dev, "Port%d: %s\n", port,
enable ? "normal operation" : "power down");
reg = read_switch_port_phy(pdev, port, MV_PHY_CONTROL);
if (enable)
reg &= ~(1 << 11); /* Normal Operation */
else
reg |= (1 << 11); /* power down */
write_switch_port_phy(pdev, port, MV_PHY_CONTROL, reg);
reg = read_switch_port_phy(pdev, port, MV_PHY_CONTROL1);
if (enable)
reg &= ~(1 << 2); /* Normal Operation */
else
reg |= (1 << 2); /* power down */
write_switch_port_phy(pdev, port, MV_PHY_CONTROL1, reg);
return 0;
}
#endif
/*
* Sysfs API
*/
struct mv88e1111_port_state *get_port_state(struct mv88e1111_priv *priv,
int port)
{
if (port == 5)
return &priv->port5;
if (port == 6)
return &priv->port6;
return NULL;
}
/*
* get MV88E6176 port number for a specific GW16083 port name
* The GW16083 ports as shown on the silkscreen are not mapped according to
* the MV88E6176 ports numbers.
*/
static int gw16083_get_port(const char* name)
{
int i;
int map[] = { 3, 2, 1, 0, 5, 6 };
if (strncasecmp(name, "ETHERNET", 8) != 0 || strlen(name) != 9)
return -1;
i = name[8] - '0';
if (i < 1 || i > 6)
return -1;
return map[i-1];
}
static ssize_t port_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mv88e1111_priv *priv = dev_get_drvdata(dev);
int port = -1;
u16 reg;
if (sscanf(attr->attr.name, "port%d", &port) != 1)
return 0;
if (port < 0 || port > 6)
return 0;
reg = read_switch_port_phy(priv->phydev, port, MV_PHY_CONTROL);
return sprintf(buf, "%s\n", (reg & (1 << 11)) ? "disabled" : "enabled");
}
#if defined(PORT_POWER_CONTROL)
static ssize_t port_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mv88e1111_priv *priv = dev_get_drvdata(dev);
int port = -1;
int val;
port = gw16083_get_port(attr->attr.name);
if (port < 0)
return 0;
if (sscanf(buf, "%d", &val) != 1)
return 0;
enable_switch_port(priv->phydev, port, val ? 1 : 0);
return count;
}
static DEVICE_ATTR(ethernet1, S_IWUSR | S_IRUGO, port_show, port_store);
static DEVICE_ATTR(ethernet2, S_IWUSR | S_IRUGO, port_show, port_store);
static DEVICE_ATTR(ethernet3, S_IWUSR | S_IRUGO, port_show, port_store);
static DEVICE_ATTR(ethernet4, S_IWUSR | S_IRUGO, port_show, port_store);
static DEVICE_ATTR(ethernet5, S_IWUSR | S_IRUGO, port_show, port_store);
static DEVICE_ATTR(ethernet6, S_IWUSR | S_IRUGO, port_show, port_store);
#else
static DEVICE_ATTR(ethernet1, S_IRUGO, port_show, NULL);
static DEVICE_ATTR(ethernet2, S_IRUGO, port_show, NULL);
static DEVICE_ATTR(ethernet3, S_IRUGO, port_show, NULL);
static DEVICE_ATTR(ethernet4, S_IRUGO, port_show, NULL);
static DEVICE_ATTR(ethernet5, S_IRUGO, port_show, NULL);
static DEVICE_ATTR(ethernet6, S_IRUGO, port_show, NULL);
#endif
static ssize_t portsfp_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mv88e1111_priv *priv = dev_get_drvdata(dev);
struct mv88e1111_port_state *state;
state = get_port_state(priv, gw16083_get_port(attr->attr.name));
if (!state)
return 0;
if (!state->sfp_present)
return 0;
return sprintf(buf, "%s\n", state->sfp_id);
}
static ssize_t portmode_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mv88e1111_priv *priv = dev_get_drvdata(dev);
struct mv88e1111_port_state *state;
state = get_port_state(priv, gw16083_get_port(attr->attr.name));
if (!state)
return 0;
return sprintf(buf, "%s\n", state->serdes ? "SFP" : "RJ45");
}
static DEVICE_ATTR(ethernet5_sfp, S_IRUGO, portsfp_show, NULL);
static DEVICE_ATTR(ethernet6_sfp, S_IRUGO, portsfp_show, NULL);
#ifdef PORT_MODE_CONTROL
static ssize_t portmode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mv88e1111_priv *priv = dev_get_drvdata(dev);
struct mv88e1111_port_state *state;
u16 reg;
int port;
port = gw16083_get_port(attr->attr.name);
state = get_port_state(priv, port);
if (!state)
return 0;
reg = read_switch_port_phy(priv->phydev, port, MII_M1111_PHY_EXT_SR);
if (strcasecmp(buf, "auto") == 0) {
reg &= ~(1<<15); /* enable auto-selection */
dev_info(&priv->client->dev, "Port%d: enable auto-selection\n",
port);
} else if (strcasecmp(buf, "RJ45") == 0) {
reg |= (1<<15); /* disable auto-selection */
reg |= 0xb; /* RGMII to Copper */
config_mv88e1111_port_sfp(priv->phydev, port, 0);
dev_info(&priv->client->dev, "Port%d: select RJ45\n", port);
} else if (strcasecmp(buf, "SFP") == 0) {
reg |= (1<<15); /* disable auto-selection */
reg |= 0x3; /* RGMII to Fiber */
config_mv88e1111_port_sfp(priv->phydev, port, 1);
dev_info(&priv->client->dev, "Port%d: select SFP\n", port);
}
write_switch_port_phy(priv->phydev, port, MII_M1111_PHY_EXT_SR, reg);
return count;
}
static DEVICE_ATTR(ethernet5_mode, S_IWUSR | S_IRUGO, portmode_show,
portmode_store);
static DEVICE_ATTR(ethernet6_mode, S_IWUSR | S_IRUGO, portmode_show,
portmode_store);
#else
static DEVICE_ATTR(ethernet5_mode, S_IRUGO, portmode_show, NULL);
static DEVICE_ATTR(ethernet6_mode, S_IRUGO, portmode_show, NULL);
#endif
/*
* PHY driver
*/
static int
mv88e6176_config_init(struct phy_device *pdev)
{
dev_dbg(&pdev->dev, "%s\n", __func__);
pdev->state = PHY_RUNNING;
return 0;
}
/* check MV88E1111 PHY status and MV88E6176 GPIO */
static int
mv88e6176_read_status(struct phy_device *pdev)
{
struct mv88e1111_priv *priv = dev_get_drvdata(&pdev->dev);
struct mv88e1111_port_state *state;
bool serdes, sfp_present, sfp_signal;
int port;
int ret = 0;
u16 gpio;
dev_dbg(&pdev->dev, "%s", __func__);
gpio = read_switch_scratch(pdev, MV_GPIO_DATA);
for (port = 5; port < 7; port++) {
serdes = (read_switch_port_phy(pdev, port, MII_M1111_PHY_EXT_SR)
& (1<<13)) ? 1 : 0;
dev_dbg(&pdev->dev, "%s: Port%d GPIO:0x%02x SerDes:%d\n",
__func__, port, gpio, serdes);
switch(port) {
case 5:
state = &priv->port5;
sfp_present = !((gpio >> 5) & 1);
sfp_signal = !((gpio >> 6) & 1);
break;
case 6:
state = &priv->port6;
sfp_present = !((gpio >> 3) & 1);
sfp_signal = !((gpio >> 4) & 1);
break;
}
/*
* on sfp_detect read/verify SFP MSA and set sfp_compat
* on sfp_signal issue link down?
* on serdes auto-select
*/
if (state->sfp_present != sfp_present) {
state->sfp_present = sfp_present;
dev_info(&pdev->dev, "Port%d: SFP %s\n",
port, sfp_present ? "inserted" : "removed");
if (state->sfp_present) {
if (gw16083_read_port_sfp(priv->client, state))
state->sfp_compat = false;
else
state->sfp_compat = true;
/* trigger a re-select/enable below */
state->serdes = !serdes;
pdev->state = PHY_RUNNING;
} else {
state->sfp_compat = false;
state->sfp_enabled = false;
pdev->state = PHY_NOLINK;
}
}
if (state->sfp_signal != sfp_signal) {
state->sfp_signal = sfp_signal;
dev_info(&pdev->dev, "Port%d: SFP signal %s\n",
port, sfp_signal ? "detected" : "lost");
}
if (state->serdes != serdes) {
state->serdes = serdes;
dev_info(&pdev->dev, "Port%d: %s auto-selected\n",
port, serdes ? "SERDES" : "copper");
/*
* if auto-selection has switched to copper
* disable serdes
*/
if (!serdes) {
config_mv88e1111_port_sfp(pdev, port, 0);
state->sfp_enabled = false;
}
}
/* if compatible SFP module and not yet enabled then enable */
if (state->sfp_compat && state->sfp_signal &&
!state->sfp_enabled)
{
if (!config_mv88e1111_port_sfp(pdev, port, 1))
state->sfp_enabled = true;
}
}
return ret;
}
static int
mv88e6176_config_aneg(struct phy_device *pdev)
{
dev_dbg(&pdev->dev, "%s", __func__);
return 0;
}
static void
mv88e6176_remove(struct phy_device *pdev)
{
dev_dbg(&pdev->dev, "%s", __func__);
device_remove_file(&pdev->dev, &dev_attr_ethernet1);
device_remove_file(&pdev->dev, &dev_attr_ethernet2);
device_remove_file(&pdev->dev, &dev_attr_ethernet3);
device_remove_file(&pdev->dev, &dev_attr_ethernet4);
device_remove_file(&pdev->dev, &dev_attr_ethernet5);
device_remove_file(&pdev->dev, &dev_attr_ethernet6);
device_remove_file(&pdev->dev, &dev_attr_ethernet5_sfp);
device_remove_file(&pdev->dev, &dev_attr_ethernet6_sfp);
device_remove_file(&pdev->dev, &dev_attr_ethernet5_mode);
device_remove_file(&pdev->dev, &dev_attr_ethernet6_mode);
sysfs_remove_link(kernel_kobj, "gw16083");
}
static int
mv88e6176_probe(struct phy_device *pdev)
{
int port;
int ret = 0;
u32 id, reg;
struct mv88e1111_priv *priv;
dev_dbg(&pdev->dev, "%s: addr=0x%02x bus=%s:%s gw16083_client=%p\n",
__func__, pdev->addr, pdev->bus->name, pdev->bus->id,
gw16083_client);
/* In single-chip addressing mode the MV88E6176 shows up on 0x10-0x16 */
if (pdev->addr != MV_BASE)
return 0;
/* i2c driver needs to be loaded first */
if (!gw16083_client)
return 0;
/* gw16083 has MV88E1676 hanging off of i210 mdio bus */
if (strcmp(pdev->bus->name, "igb_enet_mii_bus") != 0)
return 0;
//dev_info(&pdev->dev, "Detected");
dev_info(&gw16083_client->dev, "%s: MV88E6176 7-port switch detected",
pdev->bus->id);
/*
* port5/6 config: MV88E1111 PHY
* Register 20: PHY Control Register
* R20_7: add delay to RX_CLK for RXD
* R20_1: add delay to TX_CLK for TXD
* Register 24: LED Control Register
* 0x4111:
* Pulse stretch 170 to 340 ms
* Register 0: Control Register
* R0_15: phy reset
*/
for (port = 5; port < 7; port++) {
#ifndef RGMII_DELAY_ON_PHY
write_switch_port(pdev, port, MV_PORT_PHYS_CONTROL, 0xC003);
#endif
id = read_switch_port_phy(pdev, port,
MII_M1111_PHY_IDENT0) << 16;
id |= read_switch_port_phy(pdev, port, MII_M1111_PHY_IDENT1);
if ((id & MII_M1111_PHY_ID_MASK) != MII_M1111_PHY_ID) {
dev_err(&gw16083_client->dev,
"Port%d: No MV88E1111 PHY detected", port);
return 0;
//continue;
}
#ifdef RGMII_DELAY_ON_PHY
/* phy rx/tx delay */
reg = read_switch_port_phy(pdev, port, MII_M1111_PHY_EXT_CR);
reg |= (1<<1) | (1<<7);
write_switch_port_phy(pdev, port, MII_M1111_PHY_EXT_CR, reg);
#endif
/* led config */
write_switch_port_phy(pdev, port, MII_M1111_PHY_LED_CONTROL,
MII_M1111_PHY_LED_PULSE_STR);
/* reset phy */
reg = read_switch_port_phy(pdev, port, MII_M1111_PHY_CONTROL);
reg |= MII_M1111_PHY_CONTROL_RESET;
write_switch_port_phy(pdev, port, MII_M1111_PHY_CONTROL, reg);
dev_info(&gw16083_client->dev,
"Port%d MV88E111 PHY configured\n", port);
}
/*
* GPIO Configuration:
* GPIO1: FIB5_TXEN# (output)
* GPIO2: FIB6_TXEN# (output)
* GPIO3: FIB6_PRES# (input)
* GPIO4: FIB6_LOS (input)
* GPIO5: FIB5_PRES# (input)
* GPIO6: FIB5_LOS (input)
*/
write_switch_scratch(pdev, MV_GPIO_DATA, 0x06); /* GPIO[2:1] out hi */
write_switch_scratch(pdev, MV_GPIO_DIR, 0x78); /* GPIO[6:3] inp */
pdev->irq = PHY_POLL;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
memset(priv, 0, sizeof(*priv));
priv->phydev = pdev;
priv->client = gw16083_client;
priv->port5.port = 5;
priv->port6.port = 6;
dev_set_drvdata(&pdev->dev, priv);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet1);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet2);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet3);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet4);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet5);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet6);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet5_sfp);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet6_sfp);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet5_mode);
ret |= device_create_file(&pdev->dev, &dev_attr_ethernet6_mode);
if (unlikely(ret))
dev_err(&pdev->dev, "Failed creating attrs\n");
/* Add a nice symlink to the real device */
ret = sysfs_create_link(kernel_kobj, &pdev->dev.kobj, "gw16083");
dev_dbg(&pdev->dev, "initial state: GPIO=0x%02x "
"Port5_serdes=%d Port6_serdes=%d\n",
read_switch_scratch(pdev, MV_GPIO_DATA),
(read_switch_port_phy(pdev, 5, MII_M1111_PHY_EXT_SR)
& (1<<13) ? 1:0),
(read_switch_port_phy(pdev, 6, MII_M1111_PHY_EXT_SR)
& (1<<13) ? 1:0));
return ret;
}
static struct phy_driver mv88e6176_phy_driver = {
.name = "MV88E6176",
.phy_id = MV_IDENT_VALUE,
.phy_id_mask = MV_IDENT_MASK,
.features = PHY_BASIC_FEATURES,
.probe = &mv88e6176_probe,
.remove = &mv88e6176_remove,
.config_init = &mv88e6176_config_init,
.config_aneg = &mv88e6176_config_aneg,
.read_status = &mv88e6176_read_status,
.driver = { .owner = THIS_MODULE },
};
/*
* I2C driver
*/
/* See SFF-8472 */
struct sfp_msa {
/* Basic ID fields */
u8 identifier;
u8 ext_identifier;
u8 connector;
u8 transceiver[8];
u8 encoding;
u8 br_nominal;
u8 rate_identifier;
u8 length_smf_km;
u8 length_smf;
u8 length_om2;
u8 length_om1;
u8 length_om4;
u8 length_om3;
u8 vendor_name[16];
u8 transceiver2;
u8 vendor_oui[3];
u8 vendor_pn[16];
u8 vendor_rev[4];
u8 wavelength[2];
u8 resv1;
u8 cc_base;
/* extended id fields */
u8 options[2];
u8 br_max;
u8 br_min;
u8 vendor_sn[16];
u8 date_code[8];
u8 diags_type;
u8 enhanced_options;
u8 sff8472_compliance;
u8 cc_ext;
/* Vendor specific ID fields */
u8 vendor_data[32];
u8 sff8079[128];
};
enum identifier {
UNKNOWN,
GBIC,
SFF,
SFP,
XBI,
XENPACK,
XFP,
XFF,
XFP_E,
XPAK,
X2,
DWDM_SFP,
QSFP,
MAX_ID,
};
const char* id_names[] = {
"UNKONWN",
"GBIC",
"SFF",
"SFP",
NULL,
};
/* Flags for SFP modules compatible with ETH up to 1Gb */
struct sfp_flags {
u8 e1000_base_sx:1;
u8 e1000_base_lx:1;
u8 e1000_base_cx:1;
u8 e1000_base_t:1;
u8 e100_base_lx:1;
u8 e100_base_fx:1;
u8 e10_base_bx10:1;
u8 e10_base_px:1;
};
#define STRING_APPEND(str, src) \
strncat(str, src, sizeof(src)); \
for (i = 1; i < sizeof(str); i++) \
if (str[i-1] == ' ' && str[i] == ' ') \
str[i] = 0;
static int gw16083_read_port_sfp(struct i2c_client *client,
struct mv88e1111_port_state *state)
{
int ret = 0;
u8 data[256];
struct sfp_flags *eth_flags;
u8 crc;
int i;
u8 *str;
struct sfp_msa *sfp_msa = (struct sfp_msa *)data;
int port = state->port;
union i2c_smbus_data d;
dev_dbg(&client->dev, "%s Port%d\n", __func__, port);
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_I2C_BLOCK))
return -ENODEV;
d.byte = (port == 5) ? 1 : 2;
if (i2c_smbus_xfer(client->adapter, GW16083_I2C_ADDR_PCA9543,
client->flags, I2C_SMBUS_WRITE, 0,
I2C_SMBUS_BYTE_DATA, &d) < 0)
{
dev_err(&client->dev,
"Port%d: failed writing PCA9543 register\n", port);
return ret;
}
/* read all 256 bytes of SFP EEPROM */
for (i = 0; i < sizeof(data); i += I2C_SMBUS_BLOCK_MAX) {
d.block[0] = I2C_SMBUS_BLOCK_MAX;
if (i2c_smbus_xfer(client->adapter, GW16083_I2C_ADDR_SFP1,
client->flags, I2C_SMBUS_READ, i,
I2C_SMBUS_I2C_BLOCK_DATA, &d) < 0)
{
dev_err(&client->dev,
"Port%d: failed reading SFP data\n", port);
return ret;
}
memcpy(data + i, d.block + 1, I2C_SMBUS_BLOCK_MAX);
}
/* Validate checksums */
for (crc = 0, i = 0; i < 63; i++)
crc += data[i];
if (crc != sfp_msa->cc_base) {
dev_err(&client->dev, "Port%d: "
"Checksum failure for Base ID fields: 0x%02x\n", port,
crc);
#ifdef FAIL_ON_CHECKSUM_ERR
return -EINVAL;
#endif
}
for (crc = 0, i = 64; i < 95; i++)
crc += data[i];
if (crc != sfp_msa->cc_ext) {
dev_err(&client->dev, "Port%d: "
"Checksum failure for Extended ID fields: 0x%02x\n",
port, crc);
#ifdef FAIL_ON_CHECKSUM_ERR
return -EINVAL;
#endif
}
state->sfp_id[0] = 0;
for (i = 0; id_names[i]; i++) {
if (sfp_msa->identifier == i) {
sprintf(state->sfp_id, "%s: ", id_names[i]);
break;
}
}
STRING_APPEND(state->sfp_id, sfp_msa->vendor_oui);
STRING_APPEND(state->sfp_id, sfp_msa->vendor_name);
STRING_APPEND(state->sfp_id, sfp_msa->vendor_pn);
STRING_APPEND(state->sfp_id, sfp_msa->vendor_rev);
STRING_APPEND(state->sfp_id, sfp_msa->vendor_sn);
dev_info(&client->dev, "Port%d: %s\n", port, state->sfp_id);
if ((sfp_msa->identifier != GBIC) &&
(sfp_msa->identifier != SFF) &&
(sfp_msa->identifier != SFP))
{
dev_err(&client->dev, "Port%d: Unknown module identifier: %d\n",
port, sfp_msa->identifier);
return -EINVAL;
}
str = "";
eth_flags = (struct sfp_flags *)(sfp_msa->transceiver + 3);
if (eth_flags->e1000_base_sx) {
str = "1000Base-SX (Fiber)";
} else if (eth_flags->e1000_base_lx) {
str = "1000Base-LX (Fiber)";
} else if (eth_flags->e1000_base_t) {
str = "1000Base-T (Copper)";
} else if (eth_flags->e100_base_fx) {
str = "100Base-FX (Fiber) - not supported";
ret = -EINVAL;
} else {
str = "Unknown/Unsupported media type";
ret = -EINVAL;
}
if (ret)
dev_err(&client->dev, "Port%d: %s (0x%02x)\n", port, str,
sfp_msa->transceiver[3]);
else
dev_info(&client->dev, "Port%d: %s (0x%02x)\n", port, str,
sfp_msa->transceiver[3]);
return ret;
}
static int gw16083_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
dev_info(&client->dev, "GW16083 Ethernet Expansion Mezzanine\n");
if (gw16083_client) {
dev_err(&client->dev, "client already registered\n");
return -EINVAL;
}
gw16083_client = client;
ret = phy_driver_register(&mv88e6176_phy_driver);
if (ret)
dev_err(&client->dev,
"failed to register mv88e6176 phy driver: %d\n", ret);
return ret;
}
static int gw16083_remove(struct i2c_client *client)
{
dev_dbg(&client->dev, "%s\n", __func__);
phy_driver_unregister(&mv88e6176_phy_driver);
gw16083_client = NULL;
return 0;
}
static const struct of_device_id gw16083_dt_ids[] = {
{ .compatible = "gateworks,gw16083", },
{ }
};
MODULE_DEVICE_TABLE(of, gw16083_dt_ids);
static const struct i2c_device_id gw16083_id[] = {
{ "gw16083", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, gw16083_id);
static struct i2c_driver gw16083_driver = {
.driver = {
.name = "gw16083",
.of_match_table = gw16083_dt_ids,
},
.probe = gw16083_probe,
.remove = gw16083_remove,
.id_table = gw16083_id,
};
static int __init mv88e6176_init(void)
{
return i2c_add_driver(&gw16083_driver);
}
static void __exit mv88e6176_exit(void)
{
i2c_del_driver(&gw16083_driver);
}
module_init(mv88e6176_init);
module_exit(mv88e6176_exit);

View File

@ -1,123 +0,0 @@
/*
* drivers/net/phy/mv88e6176.h
*
* Driver for Marvell Switch
*
* Author: Tim Harvey
*
* Copyright (c) 2014 Tim Harvey <tharvey@gateworks.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef _GW16083_H_
#define _GW16083_H_
#define MII_MARVELL_PHY_PAGE 22
/*
* I2C Addresses
*/
#define GW16083_I2C_ADDR_SFP1 0x50
#define GW16083_I2C_ADDR_SFP2 0x51
#define GW16083_I2C_ADDR_EEPROM 0x52
#define GW16083_I2C_ADDR_PCA9543 0x70
/*
* MV88E1111 PHY Registers
*/
enum {
MII_M1111_PHY_CONTROL = 0,
MII_M1111_PHY_STATUS = 1,
MII_M1111_PHY_IDENT0 = 2,
MII_M1111_PHY_IDENT1 = 3,
MII_M1111_PHY_EXT_CR = 20,
MII_M1111_PHY_LED_CONTROL = 24,
MII_M1111_PHY_EXT_SR = 27,
};
#define MII_M1111_PHY_ID_MASK 0xfffffff0
#define MII_M1111_PHY_ID 0x01410cc0
#define MII_M1111_PHY_CONTROL_RESET (1 << 15)
#define MII_M1111_PHY_LED_DIRECT 0x4100
#define MII_M1111_PHY_LED_PULSE_STR 0x4111
#define MII_M1111_PHY_LED_COMBINE 0x411c
#define MII_M1111_RX_DELAY 0x80
#define MII_M1111_TX_DELAY 0x2
/*
* MV88E6176 Switch Registers
*/
/* PHY Addrs */
#define MV_BASE 0x10
#define MV_GLOBAL1 0x1b
#define MV_GLOBAL2 0x1c
#define MV_GLOBAL3 0x1d
/* Global2 Registers */
enum {
MV_SMI_PHY_COMMAND = 0x18,
MV_SMI_PHY_DATA = 0x19,
MV_SCRATCH_MISC = 0x1A,
};
/* Scratch And Misc Reg offsets */
enum {
MV_GPIO_MODE = 0x60,
MV_GPIO_DIR = 0x62,
MV_GPIO_DATA = 0x64,
MV_GPIO76_CNTL = 0x6B,
MV_GPIO54_CNTL = 0x6A,
MV_GPIO32_CNTL = 0x69,
MV_GPIO10_CNTL = 0x68,
MV_CONFIG0 = 0x70,
MV_CONFIG1 = 0x71,
MV_CONFIG2 = 0x72,
MV_CONFIG3 = 0x73,
};
/* PHY Registers */
enum {
MV_PHY_CONTROL = 0x00,
MV_PHY_STATUS = 0x01,
MV_PHY_IDENT0 = 0x02,
MV_PHY_IDENT1 = 0x03,
MV_PHY_ANEG = 0x04,
MV_PHY_LINK_ABILITY = 0x05,
MV_PHY_ANEG_EXPAND = 0x06,
MV_PHY_XMIT_NEXTP = 0x07,
MV_PHY_LINK_NEXTP = 0x08,
MV_PHY_CONTROL1 = 0x10,
MV_PHY_STATUS1 = 0x11,
MV_PHY_INTR_EN = 0x12,
};
/* Port Registers */
enum {
MV_PORT_STATUS = 0x00,
MV_PORT_PHYS_CONTROL = 0x01,
MV_PORT_IDENT = 0x03,
MV_PORT_CONTROL = 0x04,
MV_PORT_VLANMAP = 0x06,
MV_PORT_ASSOC = 0x0b,
MV_PORT_RXCOUNT = 0x10,
MV_PORT_TXCOUNT = 0x11,
};
#define SMIBUSY (1<<15)
#define SMIMODE22 (1<<12)
#define SMIOP_READ (2<<10)
#define SMIOP_WRITE (1<<10)
#define DEVADDR 5
#define REGADDR 0
#define MV_IDENT_MASK 0x0000fff0
#define MV_IDENT_VALUE 0x00001760
#endif /* _GW16083_H_ */

View File

@ -1,486 +0,0 @@
From e9d6d6b62f306ba83e1441af5daf2809a6167474 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 7 May 2015 08:38:00 -0700
Subject: [PATCH] ARM: dts: Gateworks GW5510 support (i.MX6)
Add support for the Gateworks GW5510 board featuring:
* i.MX6 SoC
* up to 512MB DDR3
* up to 2GB NAND flash
* 1x miniPCIe socket (with USB)
* HDMI out (micro-HDMI)
* HDMI in (micro-HDMI) (currently supported by only vendor kernel)
* TTL level I/O (supported by GW16111 breakout board):
* I2C
* 2x UART
* CAN
* 2x DIO (GPIO/PWM)
* USB OTG
For more details see:
http://www.gateworks.com/product/item/ventana-gw5510-single-board-computer
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
arch/arm/boot/dts/Makefile | 2 +
arch/arm/boot/dts/imx6dl-gw551x.dts | 55 ++++++
arch/arm/boot/dts/imx6q-gw551x.dts | 55 ++++++
arch/arm/boot/dts/imx6qdl-gw551x.dtsi | 314 ++++++++++++++++++++++++++++++++++
4 files changed, 426 insertions(+)
create mode 100644 arch/arm/boot/dts/imx6dl-gw551x.dts
create mode 100644 arch/arm/boot/dts/imx6q-gw551x.dts
create mode 100644 arch/arm/boot/dts/imx6qdl-gw551x.dtsi
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -262,6 +262,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6dl-gw52xx.dtb \
imx6dl-gw53xx.dtb \
imx6dl-gw54xx.dtb \
+ imx6dl-gw551x.dtb \
imx6dl-gw552x.dtb \
imx6dl-hummingboard.dtb \
imx6dl-nitrogen6x.dtb \
@@ -288,6 +289,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-gw53xx.dtb \
imx6q-gw5400-a.dtb \
imx6q-gw54xx.dtb \
+ imx6q-gw551x.dtb \
imx6q-gw552x.dtb \
imx6q-hummingboard.dtb \
imx6q-nitrogen6x.dtb \
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-gw551x.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 Gateworks Corporation
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "imx6dl.dtsi"
+#include "imx6qdl-gw551x.dtsi"
+
+/ {
+ model = "Gateworks Ventana i.MX6 DualLite/Solo GW551X";
+ compatible = "gw,imx6dl-gw551x", "gw,ventana", "fsl,imx6dl";
+};
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-gw551x.dts
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2014 Gateworks Corporation
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "imx6q.dtsi"
+#include "imx6qdl-gw551x.dtsi"
+
+/ {
+ model = "Gateworks Ventana i.MX6 Dual/Quad GW551X";
+ compatible = "gw,imx6q-gw551x", "gw,ventana", "fsl,imx6q";
+};
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-gw551x.dtsi
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2014 Gateworks Corporation
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ /* these are used by bootloader for disabling nodes */
+ aliases {
+ led0 = &led0;
+ nand = &gpmi;
+ ssi0 = &ssi1;
+ usb0 = &usbh1;
+ usb1 = &usbotg;
+ };
+
+ chosen {
+ bootargs = "console=ttymxc1,115200";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_leds>;
+
+ led0: user1 {
+ label = "user1";
+ gpios = <&gpio4 7 GPIO_ACTIVE_LOW>;
+ default-state = "on";
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ memory {
+ reg = <0x10000000 0x20000000>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_5p0v: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "5P0V";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ reg_usb_h1_vbus: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "usb_h1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ reg_usb_otg_vbus: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+ };
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "okay";
+};
+
+&gpmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpmi_nand>;
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c3>;
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ eeprom1: eeprom@50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+
+ eeprom2: eeprom@51 {
+ compatible = "atmel,24c02";
+ reg = <0x51>;
+ pagesize = <16>;
+ };
+
+ eeprom3: eeprom@52 {
+ compatible = "atmel,24c02";
+ reg = <0x52>;
+ pagesize = <16>;
+ };
+
+ eeprom4: eeprom@53 {
+ compatible = "atmel,24c02";
+ reg = <0x53>;
+ pagesize = <16>;
+ };
+
+ gpio: pca9555@23 {
+ compatible = "nxp,pca9555";
+ reg = <0x23>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ rtc: ds1672@68 {
+ compatible = "dallas,ds1672";
+ reg = <0x68>;
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+
+ gpio_exp: pca9555@24 {
+ compatible = "nxp,pca9555";
+ reg = <0x24>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+};
+
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie>;
+ reset-gpio = <&gpio1 0 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&ssi1 {
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "okay";
+};
+
+&usbotg {
+ vbus-supply = <&reg_usb_otg_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg>;
+ disable-over-current;
+ status = "okay";
+};
+
+&usbh1 {
+ vbus-supply = <&reg_usb_h1_vbus>;
+ status = "okay";
+};
+
+&iomuxc {
+ imx6qdl-gw51xx {
+ pinctrl_flexcan1: flexcan1grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b1
+ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b1
+ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x4001b0b0 /* CAN_STBY */
+ >;
+ };
+
+ pinctrl_gpio_leds: gpioledsgrp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW0__GPIO4_IO07 0x1b0b0
+ >;
+ };
+
+ pinctrl_gpmi_nand: gpminandgrp {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1
+ MX6QDL_PAD_NANDF_ALE__NAND_ALE 0xb0b1
+ MX6QDL_PAD_NANDF_WP_B__NAND_WP_B 0xb0b1
+ MX6QDL_PAD_NANDF_RB0__NAND_READY_B 0xb000
+ MX6QDL_PAD_NANDF_CS0__NAND_CE0_B 0xb0b1
+ MX6QDL_PAD_NANDF_CS1__NAND_CE1_B 0xb0b1
+ MX6QDL_PAD_SD4_CMD__NAND_RE_B 0xb0b1
+ MX6QDL_PAD_SD4_CLK__NAND_WE_B 0xb0b1
+ MX6QDL_PAD_NANDF_D0__NAND_DATA00 0xb0b1
+ MX6QDL_PAD_NANDF_D1__NAND_DATA01 0xb0b1
+ MX6QDL_PAD_NANDF_D2__NAND_DATA02 0xb0b1
+ MX6QDL_PAD_NANDF_D3__NAND_DATA03 0xb0b1
+ MX6QDL_PAD_NANDF_D4__NAND_DATA04 0xb0b1
+ MX6QDL_PAD_NANDF_D5__NAND_DATA05 0xb0b1
+ MX6QDL_PAD_NANDF_D6__NAND_DATA06 0xb0b1
+ MX6QDL_PAD_NANDF_D7__NAND_DATA07 0xb0b1
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1
+ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_pcie: pciegrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0 /* PCIE RST */
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_DAT7__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_SD4_DAT4__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+ >;
+ };
+ };
+};

View File

@ -1,26 +0,0 @@
From 57b82d9e79d77442bae3d2c13b98ceccb39fe5e2 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 5 Nov 2015 10:49:31 -0800
Subject: [PATCH 1/3] ARM: dts: imx: ventana: set GW54xx PMIC swbst regulator
as always-on
The GW54xx PMIC swbst regulator is used for LVDS power, CANbus xceiver
and HDMI DDC and is enabled by the bootloader. Set the regulator to
always-on so that Linux doesn't turn it off thinking its not needed.
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
arch/arm/boot/dts/imx6qdl-gw54xx.dtsi | 2 ++
1 file changed, 2 insertions(+)
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -260,6 +260,8 @@
swbst_reg: swbst {
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5150000>;
+ regulator-boot-on;
+ regulator-always-on;
};
snvs_reg: vsnvs {

View File

@ -1,33 +0,0 @@
From 473d0353979db3673a7aa365265ba9b00decd414 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 5 Nov 2015 10:52:53 -0800
Subject: [PATCH 2/3] ARM: dts: imx: ventana: fix GW53xx/GW54xx lvds channel
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
arch/arm/boot/dts/imx6qdl-gw53xx.dtsi | 2 +-
arch/arm/boot/dts/imx6qdl-gw54xx.dtsi | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
--- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
@@ -247,7 +247,7 @@
&ldb {
status = "okay";
- lvds-channel@1 {
+ lvds-channel@0 {
fsl,data-mapping = "spwg";
fsl,data-width = <18>;
status = "okay";
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -338,7 +338,7 @@
&ldb {
status = "okay";
- lvds-channel@1 {
+ lvds-channel@0 {
fsl,data-mapping = "spwg";
fsl,data-width = <18>;
status = "okay";

View File

@ -1,70 +0,0 @@
From d86b202436b6f3111c4c37b8701daa0764d2ca55 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 5 Nov 2015 11:10:00 -0800
Subject: [PATCH 3/3] ARM: dts: imx: ventana: Allow HDMI and LVDS to work
simultaneously
Currently it is not possible to have HDMI and LVDS working simultaneously,
because both ports try to use PLL5.
Move the LVDS clock parent to PLL3_USB_OTG, so that HDMI and LVDS can be
driven from independent sources.
With this change the LDB pixel clock goes to 68.57 MHz, which is still
within the valid range for the displays supported by the Ventana boards.
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
arch/arm/boot/dts/imx6qdl-gw52xx.dtsi | 7 +++++++
arch/arm/boot/dts/imx6qdl-gw53xx.dtsi | 7 +++++++
arch/arm/boot/dts/imx6qdl-gw54xx.dtsi | 7 +++++++
3 files changed, 21 insertions(+)
--- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
@@ -151,6 +151,13 @@
status = "okay";
};
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
--- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
@@ -152,6 +152,13 @@
status = "okay";
};
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -142,6 +142,13 @@
status = "okay";
};
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;

View File

@ -1,11 +0,0 @@
--- a/arch/arm/boot/dts/imx6dl-wandboard.dts
+++ b/arch/arm/boot/dts/imx6dl-wandboard.dts
@@ -19,4 +19,8 @@
memory {
reg = <0x10000000 0x40000000>;
};
+
+ chosen {
+ bootargs = "console=ttymxc0,115200";
+ };
};

View File

@ -1,129 +0,0 @@
Author: Tim Harvey <tharvey@gateworks.com>
Date: Thu May 15 00:12:26 2014 -0700
net: igb: add i210/i211 support for phy read/write
The i210/i211 uses the MDICNFG register for the phy address instead of the
MDIC register.
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -135,7 +135,7 @@ out:
s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
{
struct e1000_phy_info *phy = &hw->phy;
- u32 i, mdic = 0;
+ u32 i, mdicnfg, mdic = 0;
s32 ret_val = 0;
if (offset > MAX_PHY_REG_ADDRESS) {
@@ -148,11 +148,25 @@ s32 igb_read_phy_reg_mdic(struct e1000_h
* Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
*/
- mdic = ((offset << E1000_MDIC_REG_SHIFT) |
- (phy->addr << E1000_MDIC_PHY_SHIFT) |
- (E1000_MDIC_OP_READ));
+ switch (hw->mac.type) {
+ case e1000_i210:
+ case e1000_i211:
+ mdicnfg = rd32(E1000_MDICNFG);
+ mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
+ mdicnfg |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
+ wr32(E1000_MDICNFG, mdicnfg);
+ mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+ (E1000_MDIC_OP_READ));
+ break;
+ default:
+ mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_READ));
+ break;
+ }
wr32(E1000_MDIC, mdic);
+ wrfl();
/* Poll the ready bit to see if the MDI read completed
* Increasing the time out as testing showed failures with
@@ -177,6 +191,18 @@ s32 igb_read_phy_reg_mdic(struct e1000_h
*data = (u16) mdic;
out:
+ switch (hw->mac.type) {
+ /* restore MDICNFG to have phy's addr */
+ case e1000_i210:
+ case e1000_i211:
+ mdicnfg = rd32(E1000_MDICNFG);
+ mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
+ mdicnfg |= (hw->phy.addr << E1000_MDICNFG_PHY_SHIFT);
+ wr32(E1000_MDICNFG, mdicnfg);
+ break;
+ default:
+ break;
+ }
return ret_val;
}
@@ -191,7 +217,7 @@ out:
s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
{
struct e1000_phy_info *phy = &hw->phy;
- u32 i, mdic = 0;
+ u32 i, mdicnfg, mdic = 0;
s32 ret_val = 0;
if (offset > MAX_PHY_REG_ADDRESS) {
@@ -204,12 +230,27 @@ s32 igb_write_phy_reg_mdic(struct e1000_
* Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
*/
- mdic = (((u32)data) |
- (offset << E1000_MDIC_REG_SHIFT) |
- (phy->addr << E1000_MDIC_PHY_SHIFT) |
- (E1000_MDIC_OP_WRITE));
+ switch (hw->mac.type) {
+ case e1000_i210:
+ case e1000_i211:
+ mdicnfg = rd32(E1000_MDICNFG);
+ mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
+ mdicnfg |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
+ wr32(E1000_MDICNFG, mdicnfg);
+ mdic = (((u32)data) |
+ (offset << E1000_MDIC_REG_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+ break;
+ default:
+ mdic = (((u32)data) |
+ (offset << E1000_MDIC_REG_SHIFT) |
+ (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (E1000_MDIC_OP_WRITE));
+ break;
+ }
wr32(E1000_MDIC, mdic);
+ wrfl();
/* Poll the ready bit to see if the MDI read completed
* Increasing the time out as testing showed failures with
@@ -233,6 +274,18 @@ s32 igb_write_phy_reg_mdic(struct e1000_
}
out:
+ switch (hw->mac.type) {
+ /* restore MDICNFG to have phy's addr */
+ case e1000_i210:
+ case e1000_i211:
+ mdicnfg = rd32(E1000_MDICNFG);
+ mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
+ mdicnfg |= (hw->phy.addr << E1000_MDICNFG_PHY_SHIFT);
+ wr32(E1000_MDICNFG, mdicnfg);
+ break;
+ default:
+ break;
+ }
return ret_val;
}

View File

@ -1,260 +0,0 @@
From 16df7dc5901c1cb2a40f6adbd0d9423768ed8210 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 15 May 2014 00:29:18 -0700
Subject: [PATCH] net: igb: add phy read/write functions that accept phy addr
Add igb_write_reg_gs40g/igb_read_reg_gs40g that can be passed a phy address.
The existing igb_write_phy_reg_gs40g/igb_read_phy_reg_gs40g become wrappers
to this function.
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
drivers/net/ethernet/intel/igb/e1000_82575.c | 4 +-
drivers/net/ethernet/intel/igb/e1000_phy.c | 74 +++++++++++++++++++---------
drivers/net/ethernet/intel/igb/e1000_phy.h | 6 ++-
3 files changed, 58 insertions(+), 26 deletions(-)
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -2129,7 +2129,7 @@ static s32 igb_read_phy_reg_82580(struct
if (ret_val)
goto out;
- ret_val = igb_read_phy_reg_mdic(hw, offset, data);
+ ret_val = igb_read_phy_reg_mdic(hw, hw->phy.addr, offset, data);
hw->phy.ops.release(hw);
@@ -2154,7 +2154,7 @@ static s32 igb_write_phy_reg_82580(struc
if (ret_val)
goto out;
- ret_val = igb_write_phy_reg_mdic(hw, offset, data);
+ ret_val = igb_write_phy_reg_mdic(hw, hw->phy.addr, offset, data);
hw->phy.ops.release(hw);
--- a/drivers/net/ethernet/intel/igb/e1000_phy.c
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.c
@@ -132,9 +132,8 @@ out:
* Reads the MDI control regsiter in the PHY at offset and stores the
* information read to data.
**/
-s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u8 addr, u32 offset, u16 *data)
{
- struct e1000_phy_info *phy = &hw->phy;
u32 i, mdicnfg, mdic = 0;
s32 ret_val = 0;
@@ -153,14 +152,14 @@ s32 igb_read_phy_reg_mdic(struct e1000_h
case e1000_i211:
mdicnfg = rd32(E1000_MDICNFG);
mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
- mdicnfg |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
+ mdicnfg |= (addr << E1000_MDICNFG_PHY_SHIFT);
wr32(E1000_MDICNFG, mdicnfg);
mdic = ((offset << E1000_MDIC_REG_SHIFT) |
(E1000_MDIC_OP_READ));
break;
default:
mdic = ((offset << E1000_MDIC_REG_SHIFT) |
- (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (addr << E1000_MDIC_PHY_SHIFT) |
(E1000_MDIC_OP_READ));
break;
}
@@ -214,9 +213,8 @@ out:
*
* Writes data to MDI control register in the PHY at offset.
**/
-s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u8 addr, u32 offset, u16 data)
{
- struct e1000_phy_info *phy = &hw->phy;
u32 i, mdicnfg, mdic = 0;
s32 ret_val = 0;
@@ -235,7 +233,7 @@ s32 igb_write_phy_reg_mdic(struct e1000_
case e1000_i211:
mdicnfg = rd32(E1000_MDICNFG);
mdicnfg &= ~(E1000_MDICNFG_PHY_MASK);
- mdicnfg |= (phy->addr << E1000_MDICNFG_PHY_SHIFT);
+ mdicnfg |= (addr << E1000_MDICNFG_PHY_SHIFT);
wr32(E1000_MDICNFG, mdicnfg);
mdic = (((u32)data) |
(offset << E1000_MDIC_REG_SHIFT) |
@@ -244,7 +242,7 @@ s32 igb_write_phy_reg_mdic(struct e1000_
default:
mdic = (((u32)data) |
(offset << E1000_MDIC_REG_SHIFT) |
- (phy->addr << E1000_MDIC_PHY_SHIFT) |
+ (addr << E1000_MDIC_PHY_SHIFT) |
(E1000_MDIC_OP_WRITE));
break;
}
@@ -464,7 +462,7 @@ s32 igb_read_phy_reg_igp(struct e1000_hw
goto out;
if (offset > MAX_PHY_MULTI_PAGE_REG) {
- ret_val = igb_write_phy_reg_mdic(hw,
+ ret_val = igb_write_phy_reg_mdic(hw, hw->phy.addr,
IGP01E1000_PHY_PAGE_SELECT,
(u16)offset);
if (ret_val) {
@@ -473,8 +471,8 @@ s32 igb_read_phy_reg_igp(struct e1000_hw
}
}
- ret_val = igb_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
- data);
+ ret_val = igb_read_phy_reg_mdic(hw, hw->phy.addr,
+ MAX_PHY_REG_ADDRESS & offset, data);
hw->phy.ops.release(hw);
@@ -503,7 +501,7 @@ s32 igb_write_phy_reg_igp(struct e1000_h
goto out;
if (offset > MAX_PHY_MULTI_PAGE_REG) {
- ret_val = igb_write_phy_reg_mdic(hw,
+ ret_val = igb_write_phy_reg_mdic(hw, hw->phy.addr,
IGP01E1000_PHY_PAGE_SELECT,
(u16)offset);
if (ret_val) {
@@ -512,8 +510,8 @@ s32 igb_write_phy_reg_igp(struct e1000_h
}
}
- ret_val = igb_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
- data);
+ ret_val = igb_write_phy_reg_mdic(hw, hw->phy.addr,
+ MAX_PHY_REG_ADDRESS & offset, data);
hw->phy.ops.release(hw);
@@ -2464,8 +2462,9 @@ out:
}
/**
- * igb_write_phy_reg_gs40g - Write GS40G PHY register
+ * igb_write_reg_gs40g - Write GS40G PHY register
* @hw: pointer to the HW structure
+ * @addr: phy address to write to
* @offset: lower half is register offset to write to
* upper half is page to use.
* @data: data to write at register offset
@@ -2473,7 +2472,7 @@ out:
* Acquires semaphore, if necessary, then writes the data to PHY register
* at the offset. Release any acquired semaphores before exiting.
**/
-s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data)
+s32 igb_write_reg_gs40g(struct e1000_hw *hw, u8 addr, u32 offset, u16 data)
{
s32 ret_val;
u16 page = offset >> GS40G_PAGE_SHIFT;
@@ -2483,10 +2482,10 @@ s32 igb_write_phy_reg_gs40g(struct e1000
if (ret_val)
return ret_val;
- ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page);
+ ret_val = igb_write_phy_reg_mdic(hw, addr, GS40G_PAGE_SELECT, page);
if (ret_val)
goto release;
- ret_val = igb_write_phy_reg_mdic(hw, offset, data);
+ ret_val = igb_write_phy_reg_mdic(hw, addr, offset, data);
release:
hw->phy.ops.release(hw);
@@ -2494,8 +2493,24 @@ release:
}
/**
- * igb_read_phy_reg_gs40g - Read GS40G PHY register
+ * igb_write_phy_reg_gs40g - Write GS40G PHY register
+ * @hw: pointer to the HW structure
+ * @offset: lower half is register offset to write to
+ * upper half is page to use.
+ * @data: data to write at register offset
+ *
+ * Acquires semaphore, if necessary, then writes the data to PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data)
+{
+ return igb_write_reg_gs40g(hw, hw->phy.addr, offset, data);
+}
+
+/**
+ * igb_read_reg_gs40g - Read GS40G PHY register
* @hw: pointer to the HW structure
+ * @addr: phy address to read from
* @offset: lower half is register offset to read to
* upper half is page to use.
* @data: data to read at register offset
@@ -2503,7 +2518,7 @@ release:
* Acquires semaphore, if necessary, then reads the data in the PHY register
* at the offset. Release any acquired semaphores before exiting.
**/
-s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data)
+s32 igb_read_reg_gs40g(struct e1000_hw *hw, u8 addr, u32 offset, u16 *data)
{
s32 ret_val;
u16 page = offset >> GS40G_PAGE_SHIFT;
@@ -2513,10 +2528,10 @@ s32 igb_read_phy_reg_gs40g(struct e1000_
if (ret_val)
return ret_val;
- ret_val = igb_write_phy_reg_mdic(hw, GS40G_PAGE_SELECT, page);
+ ret_val = igb_write_phy_reg_mdic(hw, addr, GS40G_PAGE_SELECT, page);
if (ret_val)
goto release;
- ret_val = igb_read_phy_reg_mdic(hw, offset, data);
+ ret_val = igb_read_phy_reg_mdic(hw, addr, offset, data);
release:
hw->phy.ops.release(hw);
@@ -2524,6 +2539,21 @@ release:
}
/**
+ * igb_read_phy_reg_gs40g - Read GS40G PHY register
+ * @hw: pointer to the HW structure
+ * @offset: lower half is register offset to read to
+ * upper half is page to use.
+ * @data: data to read at register offset
+ *
+ * Acquires semaphore, if necessary, then reads the data in the PHY register
+ * at the offset. Release any acquired semaphores before exiting.
+ **/
+s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+ return igb_read_reg_gs40g(hw, hw->phy.addr, offset, data);
+}
+
+/**
* igb_set_master_slave_mode - Setup PHY for Master/slave mode
* @hw: pointer to the HW structure
*
--- a/drivers/net/ethernet/intel/igb/e1000_phy.h
+++ b/drivers/net/ethernet/intel/igb/e1000_phy.h
@@ -61,8 +61,8 @@ s32 igb_phy_has_link(struct e1000_hw *h
void igb_power_up_phy_copper(struct e1000_hw *hw);
void igb_power_down_phy_copper(struct e1000_hw *hw);
s32 igb_phy_init_script_igp3(struct e1000_hw *hw);
-s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data);
-s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data);
+s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u8 addr, u32 offset, u16 *data);
+s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u8 addr, u32 offset, u16 data);
s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data);
s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data);
s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data);
@@ -72,6 +72,8 @@ s32 igb_phy_force_speed_duplex_82580(st
s32 igb_get_cable_length_82580(struct e1000_hw *hw);
s32 igb_read_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 *data);
s32 igb_write_phy_reg_gs40g(struct e1000_hw *hw, u32 offset, u16 data);
+s32 igb_read_reg_gs40g(struct e1000_hw *hw, u8 addr, u32 offset, u16 *data);
+s32 igb_write_reg_gs40g(struct e1000_hw *hw, u8 addr, u32 offset, u16 data);
s32 igb_check_polarity_m88(struct e1000_hw *hw);
/* IGP01E1000 Specific Registers */

View File

@ -1,308 +0,0 @@
From 03855caf93f7332a3f320228ba1a0e7baae8a749 Mon Sep 17 00:00:00 2001
From: Tim Harvey <tharvey@gateworks.com>
Date: Thu, 15 May 2014 12:36:23 -0700
Subject: [PATCH] net: igb: register mii_bus for SerDes w/ external phy
If an i210 is configured for 1000BASE-BX link_mode and has an external phy
specified, then register an mii bus using the external phy address as
a mask.
An i210 hooked to an external standard phy will be configured with a link_mo
of SGMII in which case phy ops will be configured and used internall in the
igb driver for link status. However, in certain cases one might be using a
backplane SerDes connection to something that talks on the mdio bus but is
not a standard phy, such as a switch. In this case by registering an mdio
bus a phy driver can manage the device.
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
---
drivers/net/ethernet/intel/igb/e1000_82575.c | 15 +++
drivers/net/ethernet/intel/igb/e1000_hw.h | 7 ++
drivers/net/ethernet/intel/igb/igb_main.c | 168 ++++++++++++++++++++++++++-
3 files changed, 185 insertions(+), 5 deletions(-)
--- a/drivers/net/ethernet/intel/igb/e1000_82575.c
+++ b/drivers/net/ethernet/intel/igb/e1000_82575.c
@@ -598,13 +598,25 @@ static s32 igb_get_invariants_82575(stru
switch (link_mode) {
case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
hw->phy.media_type = e1000_media_type_internal_serdes;
+ if (igb_sgmii_uses_mdio_82575(hw)) {
+ u32 mdicnfg = rd32(E1000_MDICNFG);
+ mdicnfg &= E1000_MDICNFG_PHY_MASK;
+ hw->phy.addr = mdicnfg >> E1000_MDICNFG_PHY_SHIFT;
+ hw_dbg("1000BASE_KX w/ external MDIO device at 0x%x\n",
+ hw->phy.addr);
+ } else {
+ hw_dbg("1000BASE_KX");
+ }
break;
case E1000_CTRL_EXT_LINK_MODE_SGMII:
/* Get phy control interface type set (MDIO vs. I2C)*/
if (igb_sgmii_uses_mdio_82575(hw)) {
hw->phy.media_type = e1000_media_type_copper;
dev_spec->sgmii_active = true;
+ hw_dbg("SGMII with external MDIO PHY");
break;
+ } else {
+ hw_dbg("SGMII with external I2C PHY");
}
/* fall through for I2C based SGMII */
case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
@@ -621,8 +633,11 @@ static s32 igb_get_invariants_82575(stru
hw->phy.media_type = e1000_media_type_copper;
dev_spec->sgmii_active = true;
}
+ hw_dbg("SERDES with external SFP");
break;
+ } else {
+ hw_dbg("SERDES");
}
/* do not change link mode for 100BaseFX */
--- a/drivers/net/ethernet/intel/igb/e1000_hw.h
+++ b/drivers/net/ethernet/intel/igb/e1000_hw.h
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/netdevice.h>
+#include <linux/phy.h>
#include "e1000_regs.h"
#include "e1000_defines.h"
@@ -543,6 +544,12 @@ struct e1000_hw {
struct e1000_mbx_info mbx;
struct e1000_host_mng_dhcp_cookie mng_cookie;
+#ifdef CONFIG_PHYLIB
+ /* Phylib and MDIO interface */
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+ phy_interface_t phy_interface;
+#endif
union {
struct e1000_dev_spec_82575 _82575;
} dev_spec;
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -41,6 +41,7 @@
#include <linux/if_vlan.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
+#include <linux/phy.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/ip.h>
@@ -2234,6 +2235,126 @@ static s32 igb_init_i2c(struct igb_adapt
return status;
}
+
+#ifdef CONFIG_PHYLIB
+/*
+ * MMIO/PHYdev support
+ */
+
+static int igb_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct e1000_hw *hw = bus->priv;
+ u16 out;
+ int err;
+
+ err = igb_read_reg_gs40g(hw, mii_id, regnum, &out);
+ if (err)
+ return err;
+ return out;
+}
+
+static int igb_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+ u16 val)
+{
+ struct e1000_hw *hw = bus->priv;
+
+ return igb_write_reg_gs40g(hw, mii_id, regnum, val);
+}
+
+static int igb_enet_mdio_reset(struct mii_bus *bus)
+{
+ udelay(300);
+ return 0;
+}
+
+static void igb_enet_mii_link(struct net_device *netdev)
+{
+}
+
+/* Probe the mdio bus for phys and connect them */
+static int igb_enet_mii_probe(struct net_device *netdev)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ struct phy_device *phy_dev = NULL;
+ int phy_id;
+
+ /* check for attached phy */
+ for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {
+ if (hw->mii_bus->phy_map[phy_id]) {
+ phy_dev = hw->mii_bus->phy_map[phy_id];
+ break;
+ }
+ }
+ if (!phy_dev) {
+ netdev_err(netdev, "no PHY found\n");
+ return -ENODEV;
+ }
+
+ hw->phy_interface = PHY_INTERFACE_MODE_RGMII;
+ phy_dev = phy_connect(netdev, dev_name(&phy_dev->dev),
+ igb_enet_mii_link, hw->phy_interface);
+ if (IS_ERR(phy_dev)) {
+ netdev_err(netdev, "could not attach to PHY\n");
+ return PTR_ERR(phy_dev);
+ }
+
+ hw->phy_dev = phy_dev;
+ netdev_info(netdev, "igb PHY driver [%s] (mii_bus:phy_addr=%s)\n",
+ hw->phy_dev->drv->name, dev_name(&hw->phy_dev->dev));
+
+ return 0;
+}
+
+/* Create and register mdio bus */
+static int igb_enet_mii_init(struct pci_dev *pdev)
+{
+ struct mii_bus *mii_bus;
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
+ int err;
+
+ mii_bus = mdiobus_alloc();
+ if (mii_bus == NULL) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ mii_bus->name = "igb_enet_mii_bus";
+ mii_bus->read = igb_enet_mdio_read;
+ mii_bus->write = igb_enet_mdio_write;
+ mii_bus->reset = igb_enet_mdio_reset;
+ snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+ pci_name(pdev), hw->device_id + 1);
+ mii_bus->priv = hw;
+ mii_bus->parent = &pdev->dev;
+ mii_bus->phy_mask = ~(1 << hw->phy.addr);
+
+ err = mdiobus_register(mii_bus);
+ if (err) {
+ printk(KERN_ERR "failed to register mii_bus: %d\n", err);
+ goto err_out_free_mdiobus;
+ }
+ hw->mii_bus = mii_bus;
+
+ return 0;
+
+err_out_free_mdiobus:
+ mdiobus_free(mii_bus);
+err_out:
+ return err;
+}
+
+static void igb_enet_mii_remove(struct e1000_hw *hw)
+{
+ if (hw->mii_bus) {
+ mdiobus_unregister(hw->mii_bus);
+ mdiobus_free(hw->mii_bus);
+ }
+}
+#endif /* CONFIG_PHYLIB */
+
/**
* igb_probe - Device Initialization Routine
* @pdev: PCI device information struct
@@ -2656,6 +2777,13 @@ static int igb_probe(struct pci_dev *pde
}
}
pm_runtime_put_noidle(&pdev->dev);
+
+#ifdef CONFIG_PHYLIB
+ /* create and register the mdio bus if using ext phy */
+ if (rd32(E1000_MDICNFG) & E1000_MDICNFG_EXT_MDIO)
+ igb_enet_mii_init(pdev);
+#endif
+
return 0;
err_register:
@@ -2799,6 +2927,10 @@ static void igb_remove(struct pci_dev *p
struct e1000_hw *hw = &adapter->hw;
pm_runtime_get_noresume(&pdev->dev);
+#ifdef CONFIG_PHYLIB
+ if (rd32(E1000_MDICNFG) & E1000_MDICNFG_EXT_MDIO)
+ igb_enet_mii_remove(hw);
+#endif
#ifdef CONFIG_IGB_HWMON
igb_sysfs_exit(adapter);
#endif
@@ -3112,6 +3244,12 @@ static int __igb_open(struct net_device
if (!resuming)
pm_runtime_put(&pdev->dev);
+#ifdef CONFIG_PHYLIB
+ /* Probe and connect to PHY if using ext phy */
+ if (rd32(E1000_MDICNFG) & E1000_MDICNFG_EXT_MDIO)
+ igb_enet_mii_probe(netdev);
+#endif
+
/* start the watchdog. */
hw->mac.get_link_status = 1;
schedule_work(&adapter->watchdog_task);
@@ -7146,21 +7284,41 @@ void igb_alloc_rx_buffers(struct igb_rin
static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
struct igb_adapter *adapter = netdev_priv(netdev);
+ struct e1000_hw *hw = &adapter->hw;
struct mii_ioctl_data *data = if_mii(ifr);
- if (adapter->hw.phy.media_type != e1000_media_type_copper)
+ if (adapter->hw.phy.media_type != e1000_media_type_copper &&
+ !(rd32(E1000_MDICNFG) & E1000_MDICNFG_EXT_MDIO))
return -EOPNOTSUPP;
switch (cmd) {
case SIOCGMIIPHY:
- data->phy_id = adapter->hw.phy.addr;
+ data->phy_id = hw->phy.addr;
break;
case SIOCGMIIREG:
- if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
- &data->val_out))
- return -EIO;
+ if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) {
+ if (igb_read_reg_gs40g(&adapter->hw, data->phy_id,
+ data->reg_num & 0x1F,
+ &data->val_out))
+ return -EIO;
+ } else {
+ if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+ &data->val_out))
+ return -EIO;
+ }
break;
case SIOCSMIIREG:
+ if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) {
+ if (igb_write_reg_gs40g(hw, data->phy_id,
+ data->reg_num & 0x1F,
+ data->val_in))
+ return -EIO;
+ } else {
+ if (igb_write_phy_reg(hw, data->reg_num & 0x1F,
+ data->val_in))
+ return -EIO;
+ }
+ break;
default:
return -EOPNOTSUPP;
}

View File

@ -1,27 +0,0 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -293,6 +293,14 @@ endif # RTL8366_SMI
source "drivers/net/phy/b53/Kconfig"
+config GATEWORKS_GW16083
+ tristate "Gateworks GW16083 Ethernet Expansion Mezzanine"
+ ---help---
+ The Gateworks GW16083 Ethernet Expansion Mezzanine connects to a
+ Gateworks Ventana baseboard and provides a 7-port GbE managed
+ Ethernet switch with 4 dedicated GbE RJ45 ports, and 2 Gbe/SFP
+ ports"
+
endif # PHYLIB
config MICREL_KS8995MA
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_DP83640_PHY) += dp83640.o
obj-$(CONFIG_STE10XP) += ste10Xp.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
+obj-$(CONFIG_GATEWORKS_GW16083) += gw16083.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
obj-$(CONFIG_AT803X_PHY) += at803x.o

View File

@ -1,56 +0,0 @@
--- a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
@@ -158,6 +158,11 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
status = "okay";
+
+ gw16083: gw16083@52 {
+ compatible = "gateworks,gw16083";
+ reg = <0x52>;
+ };
};
&i2c3 {
--- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
@@ -225,6 +225,11 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
status = "okay";
+
+ gw16083: gw16083@52 {
+ compatible = "gateworks,gw16083";
+ reg = <0x52>;
+ };
};
&i2c3 {
--- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
@@ -226,6 +226,11 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
status = "okay";
+
+ gw16083: gw16083@52 {
+ compatible = "gateworks,gw16083";
+ reg = <0x52>;
+ };
};
&i2c3 {
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -317,6 +317,11 @@
};
};
};
+
+ gw16083: gw16083@52 {
+ compatible = "gateworks,gw16083";
+ reg = <0x52>;
+ };
};
&i2c3 {