driver: net: cpsw: add support for RGMII id mode support and RMII clock source selection

cpsw driver supports only selection of phy mode in control module
but control module has more setting like RGMII ID mode selection,
RMII clock source selection. So ported to cpsw-phy-sel driver
from kernel to u-boot.

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
This commit is contained in:
Mugunthan V N 2016-10-13 19:33:38 +05:30 committed by Joe Hershberger
parent 4b00d02558
commit ab9715303d
2 changed files with 144 additions and 14 deletions

View File

@ -225,6 +225,18 @@ struct cpdma_chan {
void *hdp, *cp, *rxfree;
};
/* AM33xx SoC specific definitions for the CONTROL port */
#define AM33XX_GMII_SEL_MODE_MII 0
#define AM33XX_GMII_SEL_MODE_RMII 1
#define AM33XX_GMII_SEL_MODE_RGMII 2
#define AM33XX_GMII_SEL_RGMII1_IDMODE BIT(4)
#define AM33XX_GMII_SEL_RGMII2_IDMODE BIT(5)
#define AM33XX_GMII_SEL_RMII1_IO_CLK_EN BIT(6)
#define AM33XX_GMII_SEL_RMII2_IO_CLK_EN BIT(7)
#define GMII_SEL_MODE_MASK 0x3
#define desc_write(desc, fld, val) __raw_writel((u32)(val), &(desc)->fld)
#define desc_read(desc, fld) __raw_readl(&(desc)->fld)
#define desc_read_ptr(desc, fld) ((void *)__raw_readl(&(desc)->fld))
@ -1150,12 +1162,129 @@ static inline fdt_addr_t cpsw_get_addr_by_node(const void *fdt, int node)
false);
}
static void cpsw_gmii_sel_am3352(struct cpsw_priv *priv,
phy_interface_t phy_mode)
{
u32 reg;
u32 mask;
u32 mode = 0;
bool rgmii_id = false;
int slave = priv->data.active_slave;
reg = readl(priv->data.gmii_sel);
switch (phy_mode) {
case PHY_INTERFACE_MODE_RMII:
mode = AM33XX_GMII_SEL_MODE_RMII;
break;
case PHY_INTERFACE_MODE_RGMII:
mode = AM33XX_GMII_SEL_MODE_RGMII;
break;
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
mode = AM33XX_GMII_SEL_MODE_RGMII;
rgmii_id = true;
break;
case PHY_INTERFACE_MODE_MII:
default:
mode = AM33XX_GMII_SEL_MODE_MII;
break;
};
mask = GMII_SEL_MODE_MASK << (slave * 2) | BIT(slave + 6);
mode <<= slave * 2;
if (priv->data.rmii_clock_external) {
if (slave == 0)
mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN;
else
mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN;
}
if (rgmii_id) {
if (slave == 0)
mode |= AM33XX_GMII_SEL_RGMII1_IDMODE;
else
mode |= AM33XX_GMII_SEL_RGMII2_IDMODE;
}
reg &= ~mask;
reg |= mode;
writel(reg, priv->data.gmii_sel);
}
static void cpsw_gmii_sel_dra7xx(struct cpsw_priv *priv,
phy_interface_t phy_mode)
{
u32 reg;
u32 mask;
u32 mode = 0;
int slave = priv->data.active_slave;
reg = readl(priv->data.gmii_sel);
switch (phy_mode) {
case PHY_INTERFACE_MODE_RMII:
mode = AM33XX_GMII_SEL_MODE_RMII;
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
mode = AM33XX_GMII_SEL_MODE_RGMII;
break;
case PHY_INTERFACE_MODE_MII:
default:
mode = AM33XX_GMII_SEL_MODE_MII;
break;
};
switch (slave) {
case 0:
mask = GMII_SEL_MODE_MASK;
break;
case 1:
mask = GMII_SEL_MODE_MASK << 4;
mode <<= 4;
break;
default:
dev_err(priv->dev, "invalid slave number...\n");
return;
}
if (priv->data.rmii_clock_external)
dev_err(priv->dev, "RMII External clock is not supported\n");
reg &= ~mask;
reg |= mode;
writel(reg, priv->data.gmii_sel);
}
static void cpsw_phy_sel(struct cpsw_priv *priv, const char *compat,
phy_interface_t phy_mode)
{
if (!strcmp(compat, "ti,am3352-cpsw-phy-sel"))
cpsw_gmii_sel_am3352(priv, phy_mode);
if (!strcmp(compat, "ti,am43xx-cpsw-phy-sel"))
cpsw_gmii_sel_am3352(priv, phy_mode);
else if (!strcmp(compat, "ti,dra7xx-cpsw-phy-sel"))
cpsw_gmii_sel_dra7xx(priv, phy_mode);
}
static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
struct cpsw_priv *priv = dev_get_priv(dev);
struct gpio_desc *mode_gpios;
const char *phy_mode;
const char *phy_sel_compat = NULL;
const void *fdt = gd->fdt_blob;
int node = dev->of_offset;
int subnode;
@ -1271,6 +1400,17 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
error("Not able to get gmii_sel reg address\n");
return -ENOENT;
}
if (fdt_get_property(fdt, subnode, "rmii-clock-ext",
NULL))
priv->data.rmii_clock_external = true;
phy_sel_compat = fdt_getprop(fdt, subnode, "compatible",
NULL);
if (!phy_sel_compat) {
error("Not able to get gmii_sel compatible\n");
return -ENOENT;
}
}
}
@ -1293,20 +1433,9 @@ static int cpsw_eth_ofdata_to_platdata(struct udevice *dev)
debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
return -EINVAL;
}
switch (pdata->phy_interface) {
case PHY_INTERFACE_MODE_MII:
writel(MII_MODE_ENABLE, priv->data.gmii_sel);
break;
case PHY_INTERFACE_MODE_RMII:
writel(RMII_MODE_ENABLE, priv->data.gmii_sel);
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
writel(RGMII_MODE_ENABLE, priv->data.gmii_sel);
break;
}
/* Select phy interface in control module */
cpsw_phy_sel(priv, phy_sel_compat, pdata->phy_interface);
return 0;
}

View File

@ -48,6 +48,7 @@ struct cpsw_platform_data {
void (*control)(int enabled);
u32 host_port_num;
u32 active_slave;
bool rmii_clock_external;
u8 version;
};