cregit-Linux how code gets into the kernel

Release 4.11 drivers/net/ethernet/stmicro/stmmac/altr_tse_pcs.c

/* Copyright Altera Corporation (C) 2016. All rights reserved.
 *
 * 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.
 *
 * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Tien Hock Loh <thloh@altera.com>
 */

#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/stmmac.h>

#include "stmmac.h"
#include "stmmac_platform.h"
#include "altr_tse_pcs.h"


#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII	0

#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII		BIT(1)

#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII		BIT(2)

#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH		2

#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK			GENMASK(1, 0)


#define TSE_PCS_CONTROL_AN_EN_MASK			BIT(12)

#define TSE_PCS_CONTROL_REG				0x00

#define TSE_PCS_CONTROL_RESTART_AN_MASK			BIT(9)

#define TSE_PCS_IF_MODE_REG				0x28

#define TSE_PCS_LINK_TIMER_0_REG			0x24

#define TSE_PCS_LINK_TIMER_1_REG			0x26

#define TSE_PCS_SIZE					0x40

#define TSE_PCS_STATUS_AN_COMPLETED_MASK		BIT(5)

#define TSE_PCS_STATUS_LINK_MASK			0x0004

#define TSE_PCS_STATUS_REG				0x02

#define TSE_PCS_SGMII_SPEED_1000			BIT(3)

#define TSE_PCS_SGMII_SPEED_100				BIT(2)

#define TSE_PCS_SGMII_SPEED_10				0x0

#define TSE_PCS_SW_RST_MASK				0x8000

#define TSE_PCS_PARTNER_ABILITY_REG			0x0A

#define TSE_PCS_PARTNER_DUPLEX_FULL			0x1000

#define TSE_PCS_PARTNER_DUPLEX_HALF			0x0000

#define TSE_PCS_PARTNER_DUPLEX_MASK			0x1000

#define TSE_PCS_PARTNER_SPEED_MASK			GENMASK(11, 10)

#define TSE_PCS_PARTNER_SPEED_1000			BIT(11)

#define TSE_PCS_PARTNER_SPEED_100			BIT(10)

#define TSE_PCS_PARTNER_SPEED_10			0x0000

#define TSE_PCS_PARTNER_SPEED_1000			BIT(11)

#define TSE_PCS_PARTNER_SPEED_100			BIT(10)

#define TSE_PCS_PARTNER_SPEED_10			0x0000

#define TSE_PCS_SGMII_SPEED_MASK			GENMASK(3, 2)

#define TSE_PCS_SGMII_LINK_TIMER_0			0x0D40

#define TSE_PCS_SGMII_LINK_TIMER_1			0x0003

#define TSE_PCS_SW_RESET_TIMEOUT			100

#define TSE_PCS_USE_SGMII_AN_MASK			BIT(1)

#define TSE_PCS_USE_SGMII_ENA				BIT(0)


#define SGMII_ADAPTER_CTRL_REG				0x00

#define SGMII_ADAPTER_DISABLE				0x0001

#define SGMII_ADAPTER_ENABLE				0x0000


#define AUTONEGO_LINK_TIMER				20


static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs) { int counter = 0; u16 val; val = readw(base + TSE_PCS_CONTROL_REG); val |= TSE_PCS_SW_RST_MASK; writew(val, base + TSE_PCS_CONTROL_REG); while (counter < TSE_PCS_SW_RESET_TIMEOUT) { val = readw(base + TSE_PCS_CONTROL_REG); val &= TSE_PCS_SW_RST_MASK; if (val == 0) break; counter++; udelay(1); } if (counter >= TSE_PCS_SW_RESET_TIMEOUT) { dev_err(pcs->dev, "PCS could not get out of sw reset\n"); return -ETIMEDOUT; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Tien Hock Loh106100.00%1100.00%
Total106100.00%1100.00%


int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs) { int ret = 0; writew(TSE_PCS_USE_SGMII_ENA, base + TSE_PCS_IF_MODE_REG); writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG); writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG); ret = tse_pcs_reset(base, pcs); if (ret == 0) writew(SGMII_ADAPTER_ENABLE, pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Tien Hock Loh76100.00%1100.00%
Total76100.00%1100.00%


static void pcs_link_timer_callback(unsigned long data) { u16 val = 0; struct tse_pcs *pcs = (struct tse_pcs *)data; void __iomem *tse_pcs_base = pcs->tse_pcs_base; void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); val &= TSE_PCS_STATUS_LINK_MASK; if (val != 0) { dev_dbg(pcs->dev, "Adapter: Link is established\n"); writew(SGMII_ADAPTER_ENABLE, sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); } else { mod_timer(&pcs->aneg_link_timer, jiffies + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); } }

Contributors

PersonTokensPropCommitsCommitProp
Tien Hock Loh102100.00%1100.00%
Total102100.00%1100.00%


static void auto_nego_timer_callback(unsigned long data) { u16 val = 0; u16 speed = 0; u16 duplex = 0; struct tse_pcs *pcs = (struct tse_pcs *)data; void __iomem *tse_pcs_base = pcs->tse_pcs_base; void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; val = readw(tse_pcs_base + TSE_PCS_STATUS_REG); val &= TSE_PCS_STATUS_AN_COMPLETED_MASK; if (val != 0) { dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n"); val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG); speed = val & TSE_PCS_PARTNER_SPEED_MASK; duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK; if (speed == TSE_PCS_PARTNER_SPEED_10 && duplex == TSE_PCS_PARTNER_DUPLEX_FULL) dev_dbg(pcs->dev, "Adapter: Link Partner is Up - 10/Full\n"); else if (speed == TSE_PCS_PARTNER_SPEED_100 && duplex == TSE_PCS_PARTNER_DUPLEX_FULL) dev_dbg(pcs->dev, "Adapter: Link Partner is Up - 100/Full\n"); else if (speed == TSE_PCS_PARTNER_SPEED_1000 && duplex == TSE_PCS_PARTNER_DUPLEX_FULL) dev_dbg(pcs->dev, "Adapter: Link Partner is Up - 1000/Full\n"); else if (speed == TSE_PCS_PARTNER_SPEED_10 && duplex == TSE_PCS_PARTNER_DUPLEX_HALF) dev_err(pcs->dev, "Adapter does not support Half Duplex\n"); else if (speed == TSE_PCS_PARTNER_SPEED_100 && duplex == TSE_PCS_PARTNER_DUPLEX_HALF) dev_err(pcs->dev, "Adapter does not support Half Duplex\n"); else if (speed == TSE_PCS_PARTNER_SPEED_1000 && duplex == TSE_PCS_PARTNER_DUPLEX_HALF) dev_err(pcs->dev, "Adapter does not support Half Duplex\n"); else dev_err(pcs->dev, "Adapter: Invalid Partner Speed and Duplex\n"); if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL && (speed == TSE_PCS_PARTNER_SPEED_10 || speed == TSE_PCS_PARTNER_SPEED_100 || speed == TSE_PCS_PARTNER_SPEED_1000)) writew(SGMII_ADAPTER_ENABLE, sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); } else { val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); val |= TSE_PCS_CONTROL_RESTART_AN_MASK; writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); tse_pcs_reset(tse_pcs_base, pcs); mod_timer(&pcs->aneg_link_timer, jiffies + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); } }

Contributors

PersonTokensPropCommitsCommitProp
Tien Hock Loh311100.00%1100.00%
Total311100.00%1100.00%


static void aneg_link_timer_callback(unsigned long data) { struct tse_pcs *pcs = (struct tse_pcs *)data; if (pcs->autoneg == AUTONEG_ENABLE) auto_nego_timer_callback(data); else if (pcs->autoneg == AUTONEG_DISABLE) pcs_link_timer_callback(data); }

Contributors

PersonTokensPropCommitsCommitProp
Tien Hock Loh49100.00%1100.00%
Total49100.00%1100.00%


void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev, unsigned int speed) { void __iomem *tse_pcs_base = pcs->tse_pcs_base; void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base; u32 val; writew(SGMII_ADAPTER_ENABLE, sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); pcs->autoneg = phy_dev->autoneg; if (phy_dev->autoneg == AUTONEG_ENABLE) { val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); val |= TSE_PCS_CONTROL_AN_EN_MASK; writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); val |= TSE_PCS_USE_SGMII_AN_MASK; writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); val |= TSE_PCS_CONTROL_RESTART_AN_MASK; tse_pcs_reset(tse_pcs_base, pcs); setup_timer(&pcs->aneg_link_timer, aneg_link_timer_callback, (unsigned long)pcs); mod_timer(&pcs->aneg_link_timer, jiffies + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); } else if (phy_dev->autoneg == AUTONEG_DISABLE) { val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG); val &= ~TSE_PCS_CONTROL_AN_EN_MASK; writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG); val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); val &= ~TSE_PCS_USE_SGMII_AN_MASK; writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG); val &= ~TSE_PCS_SGMII_SPEED_MASK; switch (speed) { case 1000: val |= TSE_PCS_SGMII_SPEED_1000; break; case 100: val |= TSE_PCS_SGMII_SPEED_100; break; case 10: val |= TSE_PCS_SGMII_SPEED_10; break; default: return; } writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG); tse_pcs_reset(tse_pcs_base, pcs); setup_timer(&pcs->aneg_link_timer, aneg_link_timer_callback, (unsigned long)pcs); mod_timer(&pcs->aneg_link_timer, jiffies + msecs_to_jiffies(AUTONEGO_LINK_TIMER)); } }

Contributors

PersonTokensPropCommitsCommitProp
Tien Hock Loh312100.00%1100.00%
Total312100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Tien Hock Loh114899.83%150.00%
Jia Jie Ho20.17%150.00%
Total1150100.00%2100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.