Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f659aee authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'stmmac-next'



Giuseppe Cavallaro says:

====================
stmmac: rework and enhance the PCS support

The 3.xx and 4.xx synopsys gmacs have a very similar
PCS embedded module and they share almost the same registers;
for example:
  AN_Control, AN_Status, AN_Advertisement, AN_Link_Partner_Ability,
  AN_Expansion, TBI_Extended_Status.

Just the RGMII/SMII Control/Status register differs.

So these patches aim to reorganize and enhance the PCS support;
to do that, some small inline functions have been provided and
also some rework to the PCS ISR part has been done.

In the end, the SGMII for MAC2MAC connection has been introduced.

All patches have been built on top of net-next git and, as for
the previous version, not fully tested.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a5e4bd99 02e57b9d
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -47,6 +47,9 @@ Optional properties:
				supported by this device instance
- snps,perfect-filter-entries:	Number of perfect filter entries supported
				by this device instance
- snps,ps-speed: port selection speed that can be passed to the core when
		 PCS is supported. For example, this is used in case of SGMII
		 and MAC2MAC connection.
- AXI BUS Mode parameters: below the list of all the parameters to program the
			   AXI register inside the DMA module:
	- snps,lpi_en: enable Low Power Interface
+1 −0
Original line number Diff line number Diff line
@@ -285,6 +285,7 @@ Please see the following document:
 o mmc_core.c/mmc.h: Management MAC Counters;
 o stmmac_hwtstamp.c: HW timestamp support for PTP;
 o stmmac_ptp.c: PTP 1588 clock;
 o stmmac_pcs.h: Physical Coding Sublayer common implementation;
 o dwmac-<XXX>.c: these are for the platform glue-logic file; e.g. dwmac-sti.c
   for STMicroelectronics SoCs.

+14 −5
Original line number Diff line number Diff line
@@ -232,6 +232,11 @@ struct stmmac_extra_stats {
#define DMA_HW_FEAT_ACTPHYIF	0x70000000	/* Active/selected PHY iface */
#define DEFAULT_DMA_PBL		8

/* PCS status and mask defines */
#define	PCS_ANE_IRQ		BIT(2)	/* PCS Auto-Negotiation */
#define	PCS_LINK_IRQ		BIT(1)	/* PCS Link */
#define	PCS_RGSMIIIS_IRQ	BIT(0)	/* RGMII or SMII Interrupt */

/* Max/Min RI Watchdog Timer count value */
#define MAX_DMA_RIWT		0xff
#define MIN_DMA_RIWT		0x20
@@ -272,9 +277,6 @@ enum dma_irq_status {
#define	CORE_IRQ_RX_PATH_IN_LPI_MODE	(1 << 2)
#define	CORE_IRQ_RX_PATH_EXIT_LPI_MODE	(1 << 3)

#define	CORE_PCS_ANE_COMPLETE		(1 << 5)
#define	CORE_PCS_LINK_STATUS		(1 << 6)
#define	CORE_RGMII_IRQ			(1 << 7)
#define CORE_IRQ_MTL_RX_OVERFLOW	BIT(8)

/* Physical Coding Sublayer */
@@ -469,9 +471,12 @@ struct stmmac_ops {
	void (*reset_eee_mode)(struct mac_device_info *hw);
	void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw);
	void (*set_eee_pls)(struct mac_device_info *hw, int link);
	void (*ctrl_ane)(struct mac_device_info *hw, bool restart);
	void (*get_adv)(struct mac_device_info *hw, struct rgmii_adv *adv);
	void (*debug)(void __iomem *ioaddr, struct stmmac_extra_stats *x);
	/* PCS calls */
	void (*pcs_ctrl_ane)(void __iomem *ioaddr, bool ane, bool srgmi_ral,
			     bool loopback);
	void (*pcs_rane)(void __iomem *ioaddr, bool restart);
	void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv);
};

/* PTP and HW Timer helpers */
@@ -524,6 +529,9 @@ struct mac_device_info {
	int unicast_filter_entries;
	int mcast_bits_log2;
	unsigned int rx_csum;
	unsigned int pcs;
	unsigned int pmt;
	unsigned int ps;
};

struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins,
@@ -546,6 +554,7 @@ void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable);

void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);

extern const struct stmmac_mode_ops ring_mode_ops;
extern const struct stmmac_mode_ops chain_mode_ops;
extern const struct stmmac_desc_ops dwmac4_desc_ops;
+37 −49
Original line number Diff line number Diff line
@@ -38,19 +38,26 @@
#define GMAC_WAKEUP_FILTER	0x00000028	/* Wake-up Frame Filter */

#define GMAC_INT_STATUS		0x00000038	/* interrupt status register */
enum dwmac1000_irq_status {
	lpiis_irq = 0x400,
	time_stamp_irq = 0x0200,
	mmc_rx_csum_offload_irq = 0x0080,
	mmc_tx_irq = 0x0040,
	mmc_rx_irq = 0x0020,
	mmc_irq = 0x0010,
	pmt_irq = 0x0008,
	pcs_ane_irq = 0x0004,
	pcs_link_irq = 0x0002,
	rgmii_irq = 0x0001,
};
#define GMAC_INT_MASK		0x0000003c	/* interrupt mask register */
#define GMAC_INT_STATUS_PMT	BIT(3)
#define GMAC_INT_STATUS_MMCIS	BIT(4)
#define GMAC_INT_STATUS_MMCRIS	BIT(5)
#define GMAC_INT_STATUS_MMCTIS	BIT(6)
#define GMAC_INT_STATUS_MMCCSUM	BIT(7)
#define GMAC_INT_STATUS_TSTAMP	BIT(9)
#define GMAC_INT_STATUS_LPIIS	BIT(10)

/* interrupt mask register */
#define	GMAC_INT_MASK		0x0000003c
#define	GMAC_INT_DISABLE_RGMII		BIT(0)
#define	GMAC_INT_DISABLE_PCSLINK	BIT(1)
#define	GMAC_INT_DISABLE_PCSAN		BIT(2)
#define	GMAC_INT_DISABLE_PMT		BIT(3)
#define	GMAC_INT_DISABLE_TIMESTAMP	BIT(9)
#define	GMAC_INT_DISABLE_PCS	(GMAC_INT_DISABLE_RGMII | \
				 GMAC_INT_DISABLE_PCSLINK | \
				 GMAC_INT_DISABLE_PCSAN)
#define	GMAC_INT_DEFAULT_MASK	(GMAC_INT_DISABLE_TIMESTAMP | \
				 GMAC_INT_DISABLE_PCS)

/* PMT Control and Status */
#define GMAC_PMT		0x0000002c
@@ -90,42 +97,23 @@ enum power_event {
				(reg * 8))
#define GMAC_MAX_PERFECT_ADDRESSES	1

/* PCS registers (AN/TBI/SGMII/RGMII) offset */
#define GMAC_AN_CTRL	0x000000c0	/* AN control */
#define GMAC_AN_STATUS	0x000000c4	/* AN status */
#define GMAC_ANE_ADV	0x000000c8	/* Auto-Neg. Advertisement */
#define GMAC_ANE_LPA	0x000000cc	/* Auto-Neg. link partener ability */
#define GMAC_ANE_EXP	0x000000d0	/* ANE expansion */
#define GMAC_TBI	0x000000d4	/* TBI extend status */
#define GMAC_S_R_GMII	0x000000d8	/* SGMII RGMII status */

/* AN Configuration defines */
#define GMAC_AN_CTRL_RAN	0x00000200	/* Restart Auto-Negotiation */
#define GMAC_AN_CTRL_ANE	0x00001000	/* Auto-Negotiation Enable */
#define GMAC_AN_CTRL_ELE	0x00004000	/* External Loopback Enable */
#define GMAC_AN_CTRL_ECD	0x00010000	/* Enable Comma Detect */
#define GMAC_AN_CTRL_LR		0x00020000	/* Lock to Reference */
#define GMAC_AN_CTRL_SGMRAL	0x00040000	/* SGMII RAL Control */

/* AN Status defines */
#define GMAC_AN_STATUS_LS	0x00000004	/* Link Status 0:down 1:up */
#define GMAC_AN_STATUS_ANA	0x00000008	/* Auto-Negotiation Ability */
#define GMAC_AN_STATUS_ANC	0x00000020	/* Auto-Negotiation Complete */
#define GMAC_AN_STATUS_ES	0x00000100	/* Extended Status */

/* Register 54 (SGMII/RGMII status register) */
#define GMAC_S_R_GMII_LINK		0x8
#define GMAC_S_R_GMII_SPEED		0x5
#define GMAC_S_R_GMII_SPEED_SHIFT	0x1
#define GMAC_S_R_GMII_MODE		0x1
#define GMAC_S_R_GMII_SPEED_125		2
#define GMAC_S_R_GMII_SPEED_25		1

/* Common ADV and LPA defines */
#define GMAC_ANE_FD		(1 << 5)
#define GMAC_ANE_HD		(1 << 6)
#define GMAC_ANE_PSE		(3 << 7)
#define GMAC_ANE_PSE_SHIFT	7
#define GMAC_PCS_BASE		0x000000c0	/* PCS register base */
#define GMAC_RGSMIIIS		0x000000d8	/* RGMII/SMII status */

/* SGMII/RGMII status register */
#define GMAC_RGSMIIIS_LNKMODE		BIT(0)
#define GMAC_RGSMIIIS_SPEED		GENMASK(2, 1)
#define GMAC_RGSMIIIS_SPEED_SHIFT	1
#define GMAC_RGSMIIIS_LNKSTS		BIT(3)
#define GMAC_RGSMIIIS_JABTO		BIT(4)
#define GMAC_RGSMIIIS_FALSECARDET	BIT(5)
#define GMAC_RGSMIIIS_SMIDRXS		BIT(16)
/* LNKMOD */
#define GMAC_RGSMIIIS_LNKMOD_MASK	0x1
/* LNKSPEED */
#define GMAC_RGSMIIIS_SPEED_125		0x2
#define GMAC_RGSMIIIS_SPEED_25		0x1
#define GMAC_RGSMIIIS_SPEED_2_5		0x0

/* GMAC Configuration defines */
#define GMAC_CONTROL_2K 0x08000000	/* IEEE 802.3as 2K packets */
+82 −65
Original line number Diff line number Diff line
@@ -30,22 +30,48 @@
#include <linux/slab.h>
#include <linux/ethtool.h>
#include <asm/io.h>
#include "stmmac_pcs.h"
#include "dwmac1000.h"

static void dwmac1000_core_init(struct mac_device_info *hw, int mtu)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value = readl(ioaddr + GMAC_CONTROL);

	/* Configure GMAC core */
	value |= GMAC_CORE_INIT;

	if (mtu > 1500)
		value |= GMAC_CONTROL_2K;
	if (mtu > 2000)
		value |= GMAC_CONTROL_JE;

	if (hw->ps) {
		value |= GMAC_CONTROL_TE;

		if (hw->ps == SPEED_1000) {
			value &= ~GMAC_CONTROL_PS;
		} else {
			value |= GMAC_CONTROL_PS;

			if (hw->ps == SPEED_10)
				value &= ~GMAC_CONTROL_FES;
			else
				value |= GMAC_CONTROL_FES;
		}
	}

	writel(value, ioaddr + GMAC_CONTROL);

	/* Mask GMAC interrupts */
	writel(0x207, ioaddr + GMAC_INT_MASK);
	value = GMAC_INT_DEFAULT_MASK;

	if (hw->pmt)
		value &= ~GMAC_INT_DISABLE_PMT;
	if (hw->pcs)
		value &= ~GMAC_INT_DISABLE_PCS;

	writel(value, ioaddr + GMAC_INT_MASK);

#ifdef STMMAC_VLAN_TAG_USED
	/* Tag detection without filtering */
@@ -241,6 +267,39 @@ static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode)
	writel(pmt, ioaddr + GMAC_PMT);
}

/* RGMII or SMII interface */
static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x)
{
	u32 status;

	status = readl(ioaddr + GMAC_RGSMIIIS);
	x->irq_rgmii_n++;

	/* Check the link status */
	if (status & GMAC_RGSMIIIS_LNKSTS) {
		int speed_value;

		x->pcs_link = 1;

		speed_value = ((status & GMAC_RGSMIIIS_SPEED) >>
			       GMAC_RGSMIIIS_SPEED_SHIFT);
		if (speed_value == GMAC_RGSMIIIS_SPEED_125)
			x->pcs_speed = SPEED_1000;
		else if (speed_value == GMAC_RGSMIIIS_SPEED_25)
			x->pcs_speed = SPEED_100;
		else
			x->pcs_speed = SPEED_10;

		x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK);

		pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed,
			x->pcs_duplex ? "Full" : "Half");
	} else {
		x->pcs_link = 0;
		pr_info("Link is Down\n");
	}
}

static int dwmac1000_irq_status(struct mac_device_info *hw,
				struct stmmac_extra_stats *x)
{
@@ -249,19 +308,20 @@ static int dwmac1000_irq_status(struct mac_device_info *hw,
	int ret = 0;

	/* Not used events (e.g. MMC interrupts) are not handled. */
	if ((intr_status & mmc_tx_irq))
	if ((intr_status & GMAC_INT_STATUS_MMCTIS))
		x->mmc_tx_irq_n++;
	if (unlikely(intr_status & mmc_rx_irq))
	if (unlikely(intr_status & GMAC_INT_STATUS_MMCRIS))
		x->mmc_rx_irq_n++;
	if (unlikely(intr_status & mmc_rx_csum_offload_irq))
	if (unlikely(intr_status & GMAC_INT_STATUS_MMCCSUM))
		x->mmc_rx_csum_offload_irq_n++;
	if (unlikely(intr_status & pmt_irq)) {
	if (unlikely(intr_status & GMAC_INT_DISABLE_PMT)) {
		/* clear the PMT bits 5 and 6 by reading the PMT status reg */
		readl(ioaddr + GMAC_PMT);
		x->irq_receive_pmt_irq_n++;
	}
	/* MAC trx/rx EEE LPI entry/exit interrupts */
	if (intr_status & lpiis_irq) {

	/* MAC tx/rx EEE LPI entry/exit interrupts */
	if (intr_status & GMAC_INT_STATUS_LPIIS) {
		/* Clean LPI interrupt by reading the Reg 12 */
		ret = readl(ioaddr + LPI_CTRL_STATUS);

@@ -275,36 +335,10 @@ static int dwmac1000_irq_status(struct mac_device_info *hw,
			x->irq_rx_path_exit_lpi_mode_n++;
	}

	if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) {
		readl(ioaddr + GMAC_AN_STATUS);
		x->irq_pcs_ane_n++;
	}
	if (intr_status & rgmii_irq) {
		u32 status = readl(ioaddr + GMAC_S_R_GMII);
		x->irq_rgmii_n++;

		/* Save and dump the link status. */
		if (status & GMAC_S_R_GMII_LINK) {
			int speed_value = (status & GMAC_S_R_GMII_SPEED) >>
			    GMAC_S_R_GMII_SPEED_SHIFT;
			x->pcs_duplex = (status & GMAC_S_R_GMII_MODE);
	dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);

			if (speed_value == GMAC_S_R_GMII_SPEED_125)
				x->pcs_speed = SPEED_1000;
			else if (speed_value == GMAC_S_R_GMII_SPEED_25)
				x->pcs_speed = SPEED_100;
			else
				x->pcs_speed = SPEED_10;

			x->pcs_link = 1;
			pr_debug("%s: Link is Up - %d/%s\n", __func__,
				 (int)x->pcs_speed,
				 x->pcs_duplex ? "Full" : "Half");
		} else {
			x->pcs_link = 0;
			pr_debug("%s: Link is Down\n", __func__);
		}
	}
	if (intr_status & PCS_RGSMIIIS_IRQ)
		dwmac1000_rgsmii(ioaddr, x);

	return ret;
}
@@ -363,38 +397,20 @@ static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
	writel(value, ioaddr + LPI_TIMER_CTRL);
}

static void dwmac1000_ctrl_ane(struct mac_device_info *hw, bool restart)
static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral,
			       bool loopback)
{
	void __iomem *ioaddr = hw->pcsr;
	/* auto negotiation enable and External Loopback enable */
	u32 value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE;

	if (restart)
		value |= GMAC_AN_CTRL_RAN;

	writel(value, ioaddr + GMAC_AN_CTRL);
	dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback);
}

static void dwmac1000_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv)
static void dwmac1000_rane(void __iomem *ioaddr, bool restart)
{
	void __iomem *ioaddr = hw->pcsr;
	u32 value = readl(ioaddr + GMAC_ANE_ADV);

	if (value & GMAC_ANE_FD)
		adv->duplex = DUPLEX_FULL;
	if (value & GMAC_ANE_HD)
		adv->duplex |= DUPLEX_HALF;

	adv->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;

	value = readl(ioaddr + GMAC_ANE_LPA);

	if (value & GMAC_ANE_FD)
		adv->lp_duplex = DUPLEX_FULL;
	if (value & GMAC_ANE_HD)
		adv->lp_duplex = DUPLEX_HALF;
	dwmac_rane(ioaddr, GMAC_PCS_BASE, restart);
}

	adv->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
static void dwmac1000_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv)
{
	dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv);
}

static void dwmac1000_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x)
@@ -485,9 +501,10 @@ static const struct stmmac_ops dwmac1000_ops = {
	.reset_eee_mode = dwmac1000_reset_eee_mode,
	.set_eee_timer = dwmac1000_set_eee_timer,
	.set_eee_pls = dwmac1000_set_eee_pls,
	.ctrl_ane = dwmac1000_ctrl_ane,
	.get_adv = dwmac1000_get_adv,
	.debug = dwmac1000_debug,
	.pcs_ctrl_ane = dwmac1000_ctrl_ane,
	.pcs_rane = dwmac1000_rane,
	.pcs_get_adv_lp = dwmac1000_get_adv_lp,
};

struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins,
Loading