9
0
Fork 0

cpsw: Add devicetree probe support

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
This commit is contained in:
Sascha Hauer 2013-11-20 09:19:36 +01:00
parent 6d2f0d57be
commit 9321538ee2
1 changed files with 159 additions and 7 deletions

View File

@ -27,6 +27,10 @@
#include <linux/phy.h>
#include <errno.h>
#include <io.h>
#include <of.h>
#include <pinctrl.h>
#include <of_net.h>
#include <of_address.h>
#include <xfuncs.h>
#include <asm/mmu.h>
#include <asm/system.h>
@ -900,17 +904,23 @@ static int cpsw_recv(struct eth_device *dev)
return 0;
}
static void cpsw_slave_init_data(struct cpsw_slave *slave, int slave_num,
struct cpsw_priv *priv)
{
struct cpsw_slave_data *data = priv->data.slave_data + slave_num;
slave->phy_id = data->phy_id;
slave->phy_if = data->phy_if;
}
static void cpsw_slave_setup(struct cpsw_slave *slave, int slave_num,
struct cpsw_priv *priv)
{
void *regs = priv->regs;
struct cpsw_slave_data *data = priv->data.slave_data + slave_num;
dev_dbg(priv->dev, "* %s\n", __func__);
slave->slave_num = slave_num;
slave->phy_id = data->phy_id;
slave->phy_if = data->phy_if;
slave->regs = regs + priv->slave_ofs + priv->slave_size * slave_num;
slave->sliver = regs + priv->sliver_ofs + SLIVER_SIZE * slave_num;
}
@ -950,6 +960,130 @@ static struct cpsw_data cpsw2_data = {
.cppi_ram_ofs = 0x2000,
};
static void __iomem *phy_sel_addr;
static bool rmii_clock_external;
static int cpsw_phy_sel_init(struct cpsw_priv *priv, struct device_node *np)
{
const void *reg;
unsigned long addr;
reg = of_get_property(np, "reg", NULL);
if (!reg)
return -EINVAL;
addr = of_translate_address(np, reg);
phy_sel_addr = (void *)addr;
if (of_property_read_bool(np, "rmii-clock-ext"))
rmii_clock_external = true;
return 0;
}
/* 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_RMII2_IO_CLK_EN BIT(7)
#define AM33XX_GMII_SEL_RMII1_IO_CLK_EN BIT(6)
static void cpsw_gmii_sel_am335x(struct cpsw_slave *slave)
{
u32 reg;
u32 mask;
u32 mode = 0;
reg = readl(phy_sel_addr);
switch (slave->phy_if) {
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;
};
mask = 0x3 << (slave->slave_num * 2) | BIT(slave->slave_num + 6);
mode <<= slave->slave_num * 2;
if (rmii_clock_external) {
if (slave->slave_num == 0)
mode |= AM33XX_GMII_SEL_RMII1_IO_CLK_EN;
else
mode |= AM33XX_GMII_SEL_RMII2_IO_CLK_EN;
}
reg &= ~mask;
reg |= mode;
writel(reg, phy_sel_addr);
}
static int cpsw_probe_dt(struct cpsw_priv *priv)
{
struct device_d *dev = priv->dev;
struct device_node *np = dev->device_node, *child;
int ret, i = 0;
ret = of_property_read_u32(np, "slaves", &priv->num_slaves);
if (ret)
return ret;
priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves);
for_each_child_of_node(np, child) {
if (of_device_is_compatible(child, "ti,am3352-cpsw-phy-sel")) {
ret = cpsw_phy_sel_init(priv, child);
if (ret)
return ret;
}
if (of_device_is_compatible(child, "ti,davinci_mdio")) {
ret = of_pinctrl_select_state_default(child);
if (ret)
return ret;
}
if (!strncmp(child->name, "slave", 5)) {
struct cpsw_slave *slave = &priv->slaves[i];
uint32_t phy_id[2];
ret = of_property_read_u32_array(child, "phy_id", phy_id, 2);
if (ret)
return ret;
slave->phy_id = phy_id[1];
slave->phy_if = of_get_phy_mode(child);
i++;
}
}
for (i = 0; i < 2; i++) {
struct cpsw_slave *slave = &priv->slaves[i];
cpsw_gmii_sel_am335x(slave);
}
/* Only one slave supported by this driver */
priv->num_slaves = 1;
return 0;
}
int cpsw_probe(struct device_d *dev)
{
struct cpsw_platform_data *data = (struct cpsw_platform_data *)dev->platform_data;
@ -959,6 +1093,7 @@ int cpsw_probe(struct device_d *dev)
uint64_t start;
uint32_t phy_mask;
struct cpsw_data *cpsw_data;
int ret;
dev_dbg(dev, "* %s\n", __func__);
@ -966,14 +1101,22 @@ int cpsw_probe(struct device_d *dev)
priv = xzalloc(sizeof(*priv));
priv->dev = dev;
priv->data = *data;
if (dev->device_node) {
ret = cpsw_probe_dt(priv);
if (ret)
return ret;
} else {
priv->data = *data;
priv->num_slaves = data->num_slaves;
priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves);
for_each_slave(priv, cpsw_slave_init_data, idx, priv);
}
priv->channels = 8;
priv->num_slaves = data->num_slaves;
priv->ale_entries = 1024;
edev = &priv->edev;
priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves);
priv->host_port = 0;
priv->regs = regs;
@ -1059,8 +1202,17 @@ int cpsw_probe(struct device_d *dev)
return 0;
}
static __maybe_unused struct of_device_id cpsw_dt_ids[] = {
{
.compatible = "ti,cpsw",
}, {
/* sentinel */
}
};
static struct driver_d cpsw_driver = {
.name = "cpsw",
.probe = cpsw_probe,
.of_compatible = DRV_OF_COMPAT(cpsw_dt_ids),
};
device_platform_driver(cpsw_driver);