diff options
Diffstat (limited to 'drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c')
-rw-r--r-- | drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c new file mode 100644 index 000000000000..51c32194ba88 --- /dev/null +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_xpcs.c @@ -0,0 +1,91 @@ +/* 10G controller driver for Samsung SoCs + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Author: Siva Reddy Kallam <siva.kallam@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/bitops.h> +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/phy.h> +#include "sxgbe_common.h" +#include "sxgbe_xpcs.h" + +static int sxgbe_xpcs_read(struct net_device *ndev, unsigned int reg) +{ + u32 value; + struct sxgbe_priv_data *priv = netdev_priv(ndev); + + value = readl(priv->ioaddr + XPCS_OFFSET + reg); + + return value; +} + +static int sxgbe_xpcs_write(struct net_device *ndev, int reg, int data) +{ + struct sxgbe_priv_data *priv = netdev_priv(ndev); + + writel(data, priv->ioaddr + XPCS_OFFSET + reg); + + return 0; +} + +int sxgbe_xpcs_init(struct net_device *ndev) +{ + u32 value; + + value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1); + /* 10G XAUI mode */ + sxgbe_xpcs_write(ndev, SR_PCS_CONTROL2, XPCS_TYPE_SEL_X); + sxgbe_xpcs_write(ndev, VR_PCS_MMD_XAUI_MODE_CONTROL, XPCS_XAUI_MODE); + sxgbe_xpcs_write(ndev, VR_PCS_MMD_XAUI_MODE_CONTROL, value | BIT(13)); + sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value | BIT(11)); + + do { + value = sxgbe_xpcs_read(ndev, VR_PCS_MMD_DIGITAL_STATUS); + } while ((value & XPCS_QSEQ_STATE_MPLLOFF) == XPCS_QSEQ_STATE_STABLE); + + value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1); + sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value & ~BIT(11)); + + do { + value = sxgbe_xpcs_read(ndev, VR_PCS_MMD_DIGITAL_STATUS); + } while ((value & XPCS_QSEQ_STATE_MPLLOFF) != XPCS_QSEQ_STATE_STABLE); + + return 0; +} + +int sxgbe_xpcs_init_1G(struct net_device *ndev) +{ + int value; + + /* 10GBASE-X PCS (1G) mode */ + sxgbe_xpcs_write(ndev, SR_PCS_CONTROL2, XPCS_TYPE_SEL_X); + sxgbe_xpcs_write(ndev, VR_PCS_MMD_XAUI_MODE_CONTROL, XPCS_XAUI_MODE); + value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1); + sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value & ~BIT(13)); + + value = sxgbe_xpcs_read(ndev, SR_MII_MMD_CONTROL); + sxgbe_xpcs_write(ndev, SR_MII_MMD_CONTROL, value | BIT(6)); + sxgbe_xpcs_write(ndev, SR_MII_MMD_CONTROL, value & ~BIT(13)); + value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1); + sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value | BIT(11)); + + do { + value = sxgbe_xpcs_read(ndev, VR_PCS_MMD_DIGITAL_STATUS); + } while ((value & XPCS_QSEQ_STATE_MPLLOFF) != XPCS_QSEQ_STATE_STABLE); + + value = sxgbe_xpcs_read(ndev, SR_PCS_MMD_CONTROL1); + sxgbe_xpcs_write(ndev, SR_PCS_MMD_CONTROL1, value & ~BIT(11)); + + /* Auto Negotiation cluase 37 enable */ + value = sxgbe_xpcs_read(ndev, SR_MII_MMD_CONTROL); + sxgbe_xpcs_write(ndev, SR_MII_MMD_CONTROL, value | BIT(12)); + + return 0; +} |