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: Ley Foon Tan <lftan@altera.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Ley Foon Tan 2014-08-20 14:33:33 +08:00 committed by David S. Miller
parent 6e1d0b8988
commit b4834c86e1
2 changed files with 67 additions and 0 deletions

View file

@ -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 {

View file

@ -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,
}; };