Contributors: 6
Author Tokens Token Proportion Commits Commit Proportion
Russell King 387 86.77% 7 46.67%
Giuseppe Cavallaro 40 8.97% 4 26.67%
Alexandre Torgue 9 2.02% 1 6.67%
Jose Abreu 6 1.35% 1 6.67%
Wong Vee Khee 3 0.67% 1 6.67%
Thomas Gleixner 1 0.22% 1 6.67%
Total 446 15


// SPDX-License-Identifier: GPL-2.0-only
#include "stmmac.h"
#include "stmmac_pcs.h"

/*
 * GMAC_AN_STATUS is equivalent to MII_BMSR
 * GMAC_ANE_ADV is equivalent to 802.3z MII_ADVERTISE
 * GMAC_ANE_LPA is equivalent to 802.3z MII_LPA
 * GMAC_ANE_EXP is equivalent to MII_EXPANSION
 * GMAC_TBI is equivalent to MII_ESTATUS
 *
 * ADV, LPA and EXP are only available for the TBI and RTBI modes.
 */
#define GMAC_AN_STATUS	0x04	/* AN status */
#define GMAC_ANE_ADV	0x08	/* ANE Advertisement */
#define GMAC_ANE_LPA	0x0c	/* ANE link partener ability */
#define GMAC_TBI	0x14	/* TBI extend status */

static int dwmac_integrated_pcs_enable(struct phylink_pcs *pcs)
{
	struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs);

	stmmac_mac_irq_modify(spcs->priv, 0, spcs->int_mask);

	return 0;
}

static void dwmac_integrated_pcs_disable(struct phylink_pcs *pcs)
{
	struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs);

	stmmac_mac_irq_modify(spcs->priv, spcs->int_mask, 0);
}

static void dwmac_integrated_pcs_get_state(struct phylink_pcs *pcs,
					   unsigned int neg_mode,
					   struct phylink_link_state *state)
{
	state->link = false;
}

static int dwmac_integrated_pcs_config(struct phylink_pcs *pcs,
				       unsigned int neg_mode,
				       phy_interface_t interface,
				       const unsigned long *advertising,
				       bool permit_pause_to_mac)
{
	struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs);

	dwmac_ctrl_ane(spcs->base, 0, 1, spcs->priv->hw->reverse_sgmii_enable);

	return 0;
}

static const struct phylink_pcs_ops dwmac_integrated_pcs_ops = {
	.pcs_enable = dwmac_integrated_pcs_enable,
	.pcs_disable = dwmac_integrated_pcs_disable,
	.pcs_get_state = dwmac_integrated_pcs_get_state,
	.pcs_config = dwmac_integrated_pcs_config,
};

void stmmac_integrated_pcs_irq(struct stmmac_priv *priv, u32 status,
			       struct stmmac_extra_stats *x)
{
	struct stmmac_pcs *spcs = priv->integrated_pcs;
	u32 val = readl(spcs->base + GMAC_AN_STATUS);

	if (status & PCS_ANE_IRQ) {
		x->irq_pcs_ane_n++;
		if (val & BMSR_ANEGCOMPLETE)
			dev_info(priv->device,
				 "PCS ANE process completed\n");
	}

	if (status & PCS_LINK_IRQ) {
		x->irq_pcs_link_n++;
		dev_info(priv->device, "PCS Link %s\n",
			 val & BMSR_LSTATUS ? "Up" : "Down");

		phylink_pcs_change(&spcs->pcs, val & BMSR_LSTATUS);
	}
}

int stmmac_integrated_pcs_get_phy_intf_sel(struct phylink_pcs *pcs,
					   phy_interface_t interface)
{
	if (interface == PHY_INTERFACE_MODE_SGMII)
		return PHY_INTF_SEL_SGMII;

	return -EINVAL;
}

int stmmac_integrated_pcs_init(struct stmmac_priv *priv, unsigned int offset,
			       u32 int_mask)
{
	struct stmmac_pcs *spcs;

	spcs = devm_kzalloc(priv->device, sizeof(*spcs), GFP_KERNEL);
	if (!spcs)
		return -ENOMEM;

	spcs->priv = priv;
	spcs->base = priv->ioaddr + offset;
	spcs->int_mask = int_mask;
	spcs->pcs.ops = &dwmac_integrated_pcs_ops;

	__set_bit(PHY_INTERFACE_MODE_SGMII, spcs->pcs.supported_interfaces);

	priv->integrated_pcs = spcs;

	return 0;
}