Commit b4834c86 authored by Ley Foon Tan's avatar Ley Foon Tan Committed by David S. Miller
Browse files

net: stmmac: add fix_mac_speed support for socfpga



This patch adds fix_mac_speed() support for
Altera socfpga Ethernet controller. Emac splitter is a
soft IP core in FPGA system that converts GMII interface from
Synopsys mac to RGMII/SGMII interface. This splitter core is
an optional IP if user would like to use RGMII/SGMII
interface in their system. Software needs to update a register
in splitter core when there is speed change.

Signed-off-by: default avatarLey Foon Tan <lftan@altera.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6e1d0b89
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -12,6 +12,10 @@ Required properties:
 - altr,sysmgr-syscon : Should be the phandle to the system manager node that
 - altr,sysmgr-syscon : Should be the phandle to the system manager node that
   encompasses the glue register, the register offset, and the register shift.
   encompasses the glue register, the register offset, and the register shift.


Optional properties:
altr,emac-splitter: Should be the phandle to the emac splitter soft IP node if
		DWMAC controller is connected emac splitter.

Example:
Example:


gmac0: ethernet@ff700000 {
gmac0: ethernet@ff700000 {
+63 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@


#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_net.h>
#include <linux/of_net.h>
#include <linux/phy.h>
#include <linux/phy.h>
#include <linux/regmap.h>
#include <linux/regmap.h>
@@ -30,6 +31,12 @@
#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2
#define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2
#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003
#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003


#define EMAC_SPLITTER_CTRL_REG			0x0
#define EMAC_SPLITTER_CTRL_SPEED_MASK		0x3
#define EMAC_SPLITTER_CTRL_SPEED_10		0x2
#define EMAC_SPLITTER_CTRL_SPEED_100		0x3
#define EMAC_SPLITTER_CTRL_SPEED_1000		0x0

struct socfpga_dwmac {
struct socfpga_dwmac {
	int	interface;
	int	interface;
	u32	reg_offset;
	u32	reg_offset;
@@ -37,14 +44,46 @@ struct socfpga_dwmac {
	struct	device *dev;
	struct	device *dev;
	struct regmap *sys_mgr_base_addr;
	struct regmap *sys_mgr_base_addr;
	struct reset_control *stmmac_rst;
	struct reset_control *stmmac_rst;
	void __iomem *splitter_base;
};
};


static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed)
{
	struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv;
	void __iomem *splitter_base = dwmac->splitter_base;
	u32 val;

	if (!splitter_base)
		return;

	val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG);
	val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK;

	switch (speed) {
	case 1000:
		val |= EMAC_SPLITTER_CTRL_SPEED_1000;
		break;
	case 100:
		val |= EMAC_SPLITTER_CTRL_SPEED_100;
		break;
	case 10:
		val |= EMAC_SPLITTER_CTRL_SPEED_10;
		break;
	default:
		return;
	}

	writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG);
}

static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev)
{
{
	struct device_node *np = dev->of_node;
	struct device_node *np = dev->of_node;
	struct regmap *sys_mgr_base_addr;
	struct regmap *sys_mgr_base_addr;
	u32 reg_offset, reg_shift;
	u32 reg_offset, reg_shift;
	int ret;
	int ret;
	struct device_node *np_splitter;
	struct resource res_splitter;


	dwmac->stmmac_rst = devm_reset_control_get(dev,
	dwmac->stmmac_rst = devm_reset_control_get(dev,
						  STMMAC_RESOURCE_NAME);
						  STMMAC_RESOURCE_NAME);
@@ -73,6 +112,21 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
		return -EINVAL;
		return -EINVAL;
	}
	}


	np_splitter = of_parse_phandle(np, "altr,emac-splitter", 0);
	if (np_splitter) {
		if (of_address_to_resource(np_splitter, 0, &res_splitter)) {
			dev_info(dev, "Missing emac splitter address\n");
			return -EINVAL;
		}

		dwmac->splitter_base = (void *)devm_ioremap_resource(dev,
			&res_splitter);
		if (!dwmac->splitter_base) {
			dev_info(dev, "Failed to mapping emac splitter\n");
			return -EINVAL;
		}
	}

	dwmac->reg_offset = reg_offset;
	dwmac->reg_offset = reg_offset;
	dwmac->reg_shift = reg_shift;
	dwmac->reg_shift = reg_shift;
	dwmac->sys_mgr_base_addr = sys_mgr_base_addr;
	dwmac->sys_mgr_base_addr = sys_mgr_base_addr;
@@ -91,6 +145,7 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac)


	switch (phymode) {
	switch (phymode) {
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_ID:
		val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
		val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
		break;
		break;
	case PHY_INTERFACE_MODE_MII:
	case PHY_INTERFACE_MODE_MII:
@@ -102,6 +157,13 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac)
		return -EINVAL;
		return -EINVAL;
	}
	}


	/* Overwrite val to GMII if splitter core is enabled. The phymode here
	 * is the actual phy mode on phy hardware, but phy interface from
	 * EMAC core is GMII.
	 */
	if (dwmac->splitter_base)
		val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;

	regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
	regmap_read(sys_mgr_base_addr, reg_offset, &ctrl);
	ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift);
	ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift);
	ctrl |= val << reg_shift;
	ctrl |= val << reg_shift;
@@ -196,4 +258,5 @@ const struct stmmac_of_data socfpga_gmac_data = {
	.setup = socfpga_dwmac_probe,
	.setup = socfpga_dwmac_probe,
	.init = socfpga_dwmac_init,
	.init = socfpga_dwmac_init,
	.exit = socfpga_dwmac_exit,
	.exit = socfpga_dwmac_exit,
	.fix_mac_speed = socfpga_dwmac_fix_mac_speed,
};
};