cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

altr_tse_pcs.c (7811B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Copyright Altera Corporation (C) 2016. All rights reserved.
      3 *
      4 * Author: Tien Hock Loh <thloh@altera.com>
      5 */
      6
      7#include <linux/mfd/syscon.h>
      8#include <linux/of.h>
      9#include <linux/of_address.h>
     10#include <linux/of_net.h>
     11#include <linux/phy.h>
     12#include <linux/regmap.h>
     13#include <linux/reset.h>
     14#include <linux/stmmac.h>
     15
     16#include "stmmac.h"
     17#include "stmmac_platform.h"
     18#include "altr_tse_pcs.h"
     19
     20#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII	0
     21#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII		BIT(1)
     22#define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RMII		BIT(2)
     23#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH		2
     24#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK			GENMASK(1, 0)
     25
     26#define TSE_PCS_CONTROL_AN_EN_MASK			BIT(12)
     27#define TSE_PCS_CONTROL_REG				0x00
     28#define TSE_PCS_CONTROL_RESTART_AN_MASK			BIT(9)
     29#define TSE_PCS_CTRL_AUTONEG_SGMII			0x1140
     30#define TSE_PCS_IF_MODE_REG				0x28
     31#define TSE_PCS_LINK_TIMER_0_REG			0x24
     32#define TSE_PCS_LINK_TIMER_1_REG			0x26
     33#define TSE_PCS_SIZE					0x40
     34#define TSE_PCS_STATUS_AN_COMPLETED_MASK		BIT(5)
     35#define TSE_PCS_STATUS_LINK_MASK			0x0004
     36#define TSE_PCS_STATUS_REG				0x02
     37#define TSE_PCS_SGMII_SPEED_1000			BIT(3)
     38#define TSE_PCS_SGMII_SPEED_100				BIT(2)
     39#define TSE_PCS_SGMII_SPEED_10				0x0
     40#define TSE_PCS_SW_RST_MASK				0x8000
     41#define TSE_PCS_PARTNER_ABILITY_REG			0x0A
     42#define TSE_PCS_PARTNER_DUPLEX_FULL			0x1000
     43#define TSE_PCS_PARTNER_DUPLEX_HALF			0x0000
     44#define TSE_PCS_PARTNER_DUPLEX_MASK			0x1000
     45#define TSE_PCS_PARTNER_SPEED_MASK			GENMASK(11, 10)
     46#define TSE_PCS_PARTNER_SPEED_1000			BIT(11)
     47#define TSE_PCS_PARTNER_SPEED_100			BIT(10)
     48#define TSE_PCS_PARTNER_SPEED_10			0x0000
     49#define TSE_PCS_PARTNER_SPEED_1000			BIT(11)
     50#define TSE_PCS_PARTNER_SPEED_100			BIT(10)
     51#define TSE_PCS_PARTNER_SPEED_10			0x0000
     52#define TSE_PCS_SGMII_SPEED_MASK			GENMASK(3, 2)
     53#define TSE_PCS_SGMII_LINK_TIMER_0			0x0D40
     54#define TSE_PCS_SGMII_LINK_TIMER_1			0x0003
     55#define TSE_PCS_SW_RESET_TIMEOUT			100
     56#define TSE_PCS_USE_SGMII_AN_MASK			BIT(1)
     57#define TSE_PCS_USE_SGMII_ENA				BIT(0)
     58#define TSE_PCS_IF_USE_SGMII				0x03
     59
     60#define AUTONEGO_LINK_TIMER				20
     61
     62static int tse_pcs_reset(void __iomem *base, struct tse_pcs *pcs)
     63{
     64	int counter = 0;
     65	u16 val;
     66
     67	val = readw(base + TSE_PCS_CONTROL_REG);
     68	val |= TSE_PCS_SW_RST_MASK;
     69	writew(val, base + TSE_PCS_CONTROL_REG);
     70
     71	while (counter < TSE_PCS_SW_RESET_TIMEOUT) {
     72		val = readw(base + TSE_PCS_CONTROL_REG);
     73		val &= TSE_PCS_SW_RST_MASK;
     74		if (val == 0)
     75			break;
     76		counter++;
     77		udelay(1);
     78	}
     79	if (counter >= TSE_PCS_SW_RESET_TIMEOUT) {
     80		dev_err(pcs->dev, "PCS could not get out of sw reset\n");
     81		return -ETIMEDOUT;
     82	}
     83
     84	return 0;
     85}
     86
     87int tse_pcs_init(void __iomem *base, struct tse_pcs *pcs)
     88{
     89	int ret = 0;
     90
     91	writew(TSE_PCS_IF_USE_SGMII, base + TSE_PCS_IF_MODE_REG);
     92
     93	writew(TSE_PCS_CTRL_AUTONEG_SGMII, base + TSE_PCS_CONTROL_REG);
     94
     95	writew(TSE_PCS_SGMII_LINK_TIMER_0, base + TSE_PCS_LINK_TIMER_0_REG);
     96	writew(TSE_PCS_SGMII_LINK_TIMER_1, base + TSE_PCS_LINK_TIMER_1_REG);
     97
     98	ret = tse_pcs_reset(base, pcs);
     99	if (ret == 0)
    100		writew(SGMII_ADAPTER_ENABLE,
    101		       pcs->sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
    102
    103	return ret;
    104}
    105
    106static void pcs_link_timer_callback(struct tse_pcs *pcs)
    107{
    108	u16 val = 0;
    109	void __iomem *tse_pcs_base = pcs->tse_pcs_base;
    110	void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
    111
    112	val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
    113	val &= TSE_PCS_STATUS_LINK_MASK;
    114
    115	if (val != 0) {
    116		dev_dbg(pcs->dev, "Adapter: Link is established\n");
    117		writew(SGMII_ADAPTER_ENABLE,
    118		       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
    119	} else {
    120		mod_timer(&pcs->aneg_link_timer, jiffies +
    121			  msecs_to_jiffies(AUTONEGO_LINK_TIMER));
    122	}
    123}
    124
    125static void auto_nego_timer_callback(struct tse_pcs *pcs)
    126{
    127	u16 val = 0;
    128	u16 speed = 0;
    129	u16 duplex = 0;
    130	void __iomem *tse_pcs_base = pcs->tse_pcs_base;
    131	void __iomem *sgmii_adapter_base = pcs->sgmii_adapter_base;
    132
    133	val = readw(tse_pcs_base + TSE_PCS_STATUS_REG);
    134	val &= TSE_PCS_STATUS_AN_COMPLETED_MASK;
    135
    136	if (val != 0) {
    137		dev_dbg(pcs->dev, "Adapter: Auto Negotiation is completed\n");
    138		val = readw(tse_pcs_base + TSE_PCS_PARTNER_ABILITY_REG);
    139		speed = val & TSE_PCS_PARTNER_SPEED_MASK;
    140		duplex = val & TSE_PCS_PARTNER_DUPLEX_MASK;
    141
    142		if (speed == TSE_PCS_PARTNER_SPEED_10 &&
    143		    duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
    144			dev_dbg(pcs->dev,
    145				"Adapter: Link Partner is Up - 10/Full\n");
    146		else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
    147			 duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
    148			dev_dbg(pcs->dev,
    149				"Adapter: Link Partner is Up - 100/Full\n");
    150		else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
    151			 duplex == TSE_PCS_PARTNER_DUPLEX_FULL)
    152			dev_dbg(pcs->dev,
    153				"Adapter: Link Partner is Up - 1000/Full\n");
    154		else if (speed == TSE_PCS_PARTNER_SPEED_10 &&
    155			 duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
    156			dev_err(pcs->dev,
    157				"Adapter does not support Half Duplex\n");
    158		else if (speed == TSE_PCS_PARTNER_SPEED_100 &&
    159			 duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
    160			dev_err(pcs->dev,
    161				"Adapter does not support Half Duplex\n");
    162		else if (speed == TSE_PCS_PARTNER_SPEED_1000 &&
    163			 duplex == TSE_PCS_PARTNER_DUPLEX_HALF)
    164			dev_err(pcs->dev,
    165				"Adapter does not support Half Duplex\n");
    166		else
    167			dev_err(pcs->dev,
    168				"Adapter: Invalid Partner Speed and Duplex\n");
    169
    170		if (duplex == TSE_PCS_PARTNER_DUPLEX_FULL &&
    171		    (speed == TSE_PCS_PARTNER_SPEED_10 ||
    172		     speed == TSE_PCS_PARTNER_SPEED_100 ||
    173		     speed == TSE_PCS_PARTNER_SPEED_1000))
    174			writew(SGMII_ADAPTER_ENABLE,
    175			       sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG);
    176	} else {
    177		val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
    178		val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
    179		writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
    180
    181		tse_pcs_reset(tse_pcs_base, pcs);
    182		mod_timer(&pcs->aneg_link_timer, jiffies +
    183			  msecs_to_jiffies(AUTONEGO_LINK_TIMER));
    184	}
    185}
    186
    187static void aneg_link_timer_callback(struct timer_list *t)
    188{
    189	struct tse_pcs *pcs = from_timer(pcs, t, aneg_link_timer);
    190
    191	if (pcs->autoneg == AUTONEG_ENABLE)
    192		auto_nego_timer_callback(pcs);
    193	else if (pcs->autoneg == AUTONEG_DISABLE)
    194		pcs_link_timer_callback(pcs);
    195}
    196
    197void tse_pcs_fix_mac_speed(struct tse_pcs *pcs, struct phy_device *phy_dev,
    198			   unsigned int speed)
    199{
    200	void __iomem *tse_pcs_base = pcs->tse_pcs_base;
    201	u32 val;
    202
    203	pcs->autoneg = phy_dev->autoneg;
    204
    205	if (phy_dev->autoneg == AUTONEG_ENABLE) {
    206		val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
    207		val |= TSE_PCS_CONTROL_AN_EN_MASK;
    208		writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
    209
    210		val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
    211		val |= TSE_PCS_USE_SGMII_AN_MASK;
    212		writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
    213
    214		val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
    215		val |= TSE_PCS_CONTROL_RESTART_AN_MASK;
    216
    217		tse_pcs_reset(tse_pcs_base, pcs);
    218
    219		timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback,
    220			    0);
    221		mod_timer(&pcs->aneg_link_timer, jiffies +
    222			  msecs_to_jiffies(AUTONEGO_LINK_TIMER));
    223	} else if (phy_dev->autoneg == AUTONEG_DISABLE) {
    224		val = readw(tse_pcs_base + TSE_PCS_CONTROL_REG);
    225		val &= ~TSE_PCS_CONTROL_AN_EN_MASK;
    226		writew(val, tse_pcs_base + TSE_PCS_CONTROL_REG);
    227
    228		val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
    229		val &= ~TSE_PCS_USE_SGMII_AN_MASK;
    230		writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
    231
    232		val = readw(tse_pcs_base + TSE_PCS_IF_MODE_REG);
    233		val &= ~TSE_PCS_SGMII_SPEED_MASK;
    234
    235		switch (speed) {
    236		case 1000:
    237			val |= TSE_PCS_SGMII_SPEED_1000;
    238			break;
    239		case 100:
    240			val |= TSE_PCS_SGMII_SPEED_100;
    241			break;
    242		case 10:
    243			val |= TSE_PCS_SGMII_SPEED_10;
    244			break;
    245		default:
    246			return;
    247		}
    248		writew(val, tse_pcs_base + TSE_PCS_IF_MODE_REG);
    249
    250		tse_pcs_reset(tse_pcs_base, pcs);
    251
    252		timer_setup(&pcs->aneg_link_timer, aneg_link_timer_callback,
    253			    0);
    254		mod_timer(&pcs->aneg_link_timer, jiffies +
    255			  msecs_to_jiffies(AUTONEGO_LINK_TIMER));
    256	}
    257}