* Re: [PATCH] gianfar: prevent resource conflict
2013-05-30 15:15 [PATCH] gianfar: prevent resource conflict Renaud Barbier
@ 2013-06-01 9:20 ` Sascha Hauer
2013-06-03 9:31 ` Renaud Barbier
2013-06-25 13:09 ` [PATCH v2 0/2] " Renaud Barbier
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Sascha Hauer @ 2013-06-01 9:20 UTC (permalink / raw)
To: Renaud Barbier; +Cc: barebox
On Thu, May 30, 2013 at 04:15:35PM +0100, Renaud Barbier wrote:
> On eTSEC Ethernet devices, there are three memory regions to map.
> These regions map registers to control the TSEC interfaces, PHY
> access and TBI interface.
>
> Depending on the port number and TSEC version, some of these resources
> may be shared within an instance of the driver or between instances
> of the driver.
>
> Since dev_request_mem_region returns NULL to avoid resource conflicts if
> a region is already mapped the TSEC driver fails to initialise when
> these regions are shared. This patch works around this and makes
> all three memory regions available to each instance.
>
> Below is a description of TSEC Ethernet port mapping for port 1 to 3.
> These ports are present in CPUs susch as the mpc8544 and P2020.
>
> Each port has three set of registers:
> * region 0 maps the TSEC registers.
> * region 1 maps the PHY access registers always through port 1.
> * region 2 maps the TBI interface registers.
>
> The tables below shows how registers are mapped.
> For instance, for TSEC version 1:
> - port 2/register set 1 i.e p2/reg1 is the same region as
> port 1/register set 1 i.e p1/reg1. That is they share port 1
> register set 1 as the same region.
> As well is p3/reg1, p1/reg0 and p1/reg2 uses p1/reg1.
>
> - port 2/register set 0 i.e p2/reg0 is not the same region as
> port 3/register set 0 i.e p3/reg0.
> That is p2/r0 and p3/r0 are two different regions.
> However, port 2/register 2 is the same as port 2/register 0.
>
> TSEC version 1:
> ports/registers reg0 reg1 reg2
> p1 p1/r1 p1/r1 p1/r1
> p2 p2/r0 p1/r1 p2/r0
> p3 p3/r0 p1/r1 p3/r0
>
> TSEC version2:
> ports/registers reg0 reg1 reg2
> p1 p1/r0 p1/r1 p1/r1
> p2 p2/r0 p1/r1 p2/r2
> p3 p3/r0 p1/r1 p3/r2
>
> Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
> ---
> drivers/net/gianfar.c | 19 ++++++++++++++++++-
> 1 files changed, 18 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
> index 96055bd..79113a8 100644
> --- a/drivers/net/gianfar.c
> +++ b/drivers/net/gianfar.c
> @@ -28,6 +28,8 @@
> #define RX_BUF_CNT PKTBUFSRX
> #define BUF_ALIGN 8
>
> +static void __iomem *phyregs;
> +
> /*
> * Initialize required registers to appropriate values, zeroing
> * those we don't care about (unless zero is bad, in which case,
> @@ -481,8 +483,23 @@ static int gfar_probe(struct device_d *dev)
> edev = &priv->edev;
>
> priv->regs = dev_request_mem_region(dev, 0);
> - priv->phyregs = dev_request_mem_region(dev, 1);
> + if (priv->regs == NULL)
> + priv->regs = phyregs;
the first resource is for the ethernet registers and no phy registers,
right?
> +
> + if (phyregs == NULL) {
> + phyregs = dev_request_mem_region(dev, 1);
> + if (phyregs == NULL)
> + phyregs = priv->regs;
> + }
> + priv->phyregs = phyregs;
> +
> priv->phyregs_sgmii = dev_request_mem_region(dev, 2);
> + if (priv->phyregs_sgmii == NULL) {
> + if (IS_ENABLED(CONFIG_TSECV2))
> + priv->phyregs_sgmii = priv->phyregs;
> + else
> + priv->phyregs_sgmii = priv->regs;
> + }
I think you should really register the mdio buses as separate devices
since it's the mdio buses that are shared between the different
instances, not the registers. The following may be a starting point
(untested)
From 480a54380c42d56e1b5f16fb718fe2c4a1a38ab0 Mon Sep 17 00:00:00 2001
From: Sascha Hauer <s.hauer@pengutronix.de>
Date: Sat, 1 Jun 2013 11:16:37 +0200
Subject: [PATCH] net: gfar: register mdio buses as separate devices
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/ppc/boards/freescale-p2020rdb/p2020rdb.c | 2 +
arch/ppc/mach-mpc85xx/eth-devices.c | 32 +++----
arch/ppc/mach-mpc85xx/include/mach/gianfar.h | 2 +
drivers/net/gianfar.c | 117 ++++++++++++++++++--------
drivers/net/gianfar.h | 5 +-
5 files changed, 103 insertions(+), 55 deletions(-)
diff --git a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
index edb9bcd..cc4af7f 100644
--- a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
+++ b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
@@ -65,6 +65,8 @@ static struct gfar_info_struct gfar_info[] = {
.phyaddr = 1,
.tbiana = 0,
.tbicr = 0,
+ .mdiobus = -1, /* FIXME */
+ .mdiobus_sgmii = -1, /* FIXME */
},
};
diff --git a/arch/ppc/mach-mpc85xx/eth-devices.c b/arch/ppc/mach-mpc85xx/eth-devices.c
index c6e8f36..510e57c 100644
--- a/arch/ppc/mach-mpc85xx/eth-devices.c
+++ b/arch/ppc/mach-mpc85xx/eth-devices.c
@@ -22,28 +22,28 @@
#include <common.h>
#include <driver.h>
+#include <init.h>
#include <mach/immap_85xx.h>
#include <mach/gianfar.h>
-int fsl_eth_init(int num, struct gfar_info_struct *gf)
+static int fsl_phy_init(void)
{
- struct resource *res;
+ int i;
+
+ for (i = 0; i < 4; i++)
+ add_generic_device("gfar-phy", i, NULL,
+ MDIO_BASE_ADDR + i * 0x1000, 0x1000,
+ IORESOURCE_MEM, NULL);
+ return 0;
+}
- res = xzalloc(3 * sizeof(struct resource));
- /* TSEC interface registers */
- res[0].start = GFAR_BASE_ADDR + ((num - 1) * 0x1000);
- res[0].end = res[0].start + 0x1000 - 1;
- res[0].flags = IORESOURCE_MEM;
- /* External PHY access always through eTSEC1 */
- res[1].start = MDIO_BASE_ADDR;
- res[1].end = res[1].start + 0x1000 - 1;
- res[1].flags = IORESOURCE_MEM;
- /* Access to TBI/RTBI interface. */
- res[2].start = MDIO_BASE_ADDR + ((num - 1) * 0x1000);
- res[2].end = res[2].start + 0x1000 - 1;
- res[2].flags = IORESOURCE_MEM;
+coredevice_initcall(fsl_phy_init);
- add_generic_device_res("gfar", DEVICE_ID_DYNAMIC, res, 3, gf);
+int fsl_eth_init(int num, struct gfar_info_struct *gf)
+{
+ add_generic_device("gfar", num - 1, NULL,
+ GFAR_BASE_ADDR + (num - 1) * 0x1000, 0x1000,
+ IORESOURCE_MEM, gf);
return 0;
}
diff --git a/arch/ppc/mach-mpc85xx/include/mach/gianfar.h b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
index ae31638..48dd945 100644
--- a/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
+++ b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
@@ -26,6 +26,8 @@ struct gfar_info_struct {
unsigned int phyaddr;
unsigned int tbiana;
unsigned int tbicr;
+ unsigned int mdiobus; /* mdio bus number (0..3) */
+ unsigned int mdiobus_sgmii; /* mdio bus number for sgmii (0..3) */
};
int fsl_eth_init(int num, struct gfar_info_struct *gf);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 96055bd..bb4931e 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -28,6 +28,14 @@
#define RX_BUF_CNT PKTBUFSRX
#define BUF_ALIGN 8
+struct gfar_phy {
+ void __iomem *regs;
+ struct device_d *dev;
+ struct mii_bus miibus;
+};
+
+static struct gfar_phy *phys[4];
+
/*
* Initialize required registers to appropriate values, zeroing
* those we don't care about (unless zero is bad, in which case,
@@ -184,10 +192,11 @@ static int gfar_open(struct eth_device *edev)
{
int ix;
struct gfar_private *priv = edev->priv;
+ struct gfar_phy *phy = phys[priv->mdiobus];
void __iomem *regs = priv->regs;
int ret;
- ret = phy_device_connect(edev, &priv->miibus, priv->phyaddr,
+ ret = phy_device_connect(edev, &phy->miibus, priv->phyaddr,
gfar_adjust_link, 0, PHY_INTERFACE_MODE_NA);
if (ret)
return ret;
@@ -255,17 +264,21 @@ static int gfar_set_ethaddr(struct eth_device *edev, unsigned char *mac)
}
/* Writes the given phy's reg with value, using the specified MDIO regs */
-static int gfar_local_mdio_write(void __iomem *phyregs, uint addr, uint reg,
+static int gfar_local_mdio_write(int mdiobus, uint addr, uint reg,
uint value)
{
+ struct gfar_phy *phy = phys[mdiobus];
uint64_t start;
- out_be32(phyregs + GFAR_MIIMADD_OFFSET, (addr << 8) | (reg & 0x1f));
- out_be32(phyregs + GFAR_MIIMCON_OFFSET, value);
+ if (!phy)
+ return -ENODEV;
+
+ out_be32(phy->regs + GFAR_MIIMADD_OFFSET, (addr << 8) | (reg & 0x1f));
+ out_be32(phy->regs + GFAR_MIIMCON_OFFSET, value);
start = get_time_ns();
while (!is_timeout(start, 10 * MSECOND)) {
- if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
+ if (!(in_be32(phy->regs + GFAR_MIIMMIND_OFFSET) &
GFAR_MIIMIND_BUSY))
return 0;
}
@@ -280,24 +293,28 @@ static int gfar_local_mdio_write(void __iomem *phyregs, uint addr, uint reg,
* notvalid bit cleared), and the bus to cease activity (miimind
* busy bit cleared), and then returns the value
*/
-static uint gfar_local_mdio_read(void __iomem *phyregs, uint phyid, uint regnum)
+static uint gfar_local_mdio_read(int mdiobus, uint phyid, uint regnum)
{
+ struct gfar_phy *phy = phys[mdiobus];
uint64_t start;
+ if (!phy)
+ return -ENODEV;
+
/* Put the address of the phy, and the register number into MIIMADD */
- out_be32(phyregs + GFAR_MIIMADD_OFFSET, (phyid << 8) | (regnum & 0x1f));
+ out_be32(phy->regs + GFAR_MIIMADD_OFFSET, (phyid << 8) | (regnum & 0x1f));
/* Clear the command register, and wait */
- out_be32(phyregs + GFAR_MIIMCOM_OFFSET, 0);
+ out_be32(phy->regs + GFAR_MIIMCOM_OFFSET, 0);
/* Initiate a read command, and wait */
- out_be32(phyregs + GFAR_MIIMCOM_OFFSET, GFAR_MIIM_READ_COMMAND);
+ out_be32(phy->regs + GFAR_MIIMCOM_OFFSET, GFAR_MIIM_READ_COMMAND);
start = get_time_ns();
while (!is_timeout(start, 10 * MSECOND)) {
- if (!(in_be32(phyregs + GFAR_MIIMMIND_OFFSET) &
+ if (!(in_be32(phy->regs + GFAR_MIIMMIND_OFFSET) &
(GFAR_MIIMIND_NOTVALID | GFAR_MIIMIND_BUSY)))
- return in_be32(phyregs + GFAR_MIIMSTAT_OFFSET);
+ return in_be32(phy->regs + GFAR_MIIMSTAT_OFFSET);
}
return -EIO;
@@ -305,13 +322,13 @@ static uint gfar_local_mdio_read(void __iomem *phyregs, uint phyid, uint regnum)
static void gfar_configure_serdes(struct gfar_private *priv)
{
- gfar_local_mdio_write(priv->phyregs_sgmii,
+ gfar_local_mdio_write(priv->mdiobus_sgmii,
in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_ANA,
priv->tbiana);
- gfar_local_mdio_write(priv->phyregs_sgmii,
+ gfar_local_mdio_write(priv->mdiobus_sgmii,
in_be32(priv->regs + GFAR_TBIPA_OFFSET),
GFAR_TBI_TBICON, GFAR_TBICON_CLK_SELECT);
- gfar_local_mdio_write(priv->phyregs_sgmii,
+ gfar_local_mdio_write(priv->mdiobus_sgmii,
in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_CR,
priv->tbicr);
}
@@ -320,29 +337,33 @@ static void gfar_configure_serdes(struct gfar_private *priv)
static void gfar_init_phy(struct eth_device *dev)
{
struct gfar_private *priv = dev->priv;
+ struct gfar_phy *phy = phys[priv->mdiobus];
void __iomem *regs = priv->regs;
uint64_t start;
+ if (!phy)
+ return;
+
/* Assign a Physical address to the TBI */
out_be32(regs + GFAR_TBIPA_OFFSET, GFAR_TBIPA_VALUE);
/* Reset MII (due to new addresses) */
- out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
- out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
+ out_be32(phy->regs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
+ out_be32(phy->regs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
start = get_time_ns();
while (!is_timeout(start, 10 * MSECOND)) {
- if (!(in_be32(priv->phyregs + GFAR_MIIMMIND_OFFSET) &
+ if (!(in_be32(phy->regs + GFAR_MIIMMIND_OFFSET) &
GFAR_MIIMIND_BUSY))
break;
}
- gfar_local_mdio_write(priv->phyregs, priv->phyaddr, GFAR_MIIM_CR,
+ gfar_local_mdio_write(priv->mdiobus, priv->phyaddr, GFAR_MIIM_CR,
GFAR_MIIM_CR_RST);
start = get_time_ns();
while (!is_timeout(start, 10 * MSECOND)) {
- if (!(gfar_local_mdio_read(priv->phyregs, priv->phyaddr,
+ if (!(gfar_local_mdio_read(priv->mdiobus, priv->phyaddr,
GFAR_MIIM_CR) & GFAR_MIIM_CR_RST))
break;
}
@@ -433,13 +454,12 @@ static int gfar_recv(struct eth_device *edev)
/* Read a MII PHY register. */
static int gfar_miiphy_read(struct mii_bus *bus, int addr, int reg)
{
- struct device_d *dev = bus->parent;
- struct gfar_private *priv = bus->priv;
+ struct gfar_phy *phy = bus->priv;
int ret;
- ret = gfar_local_mdio_read(priv->phyregs, addr, reg);
+ ret = gfar_local_mdio_read(phy->dev->id, addr, reg);
if (ret == -EIO)
- dev_err(dev, "Can't read PHY at address %d\n", addr);
+ dev_err(phy->dev, "Can't read PHY at address %d\n", addr);
return ret;
}
@@ -448,15 +468,14 @@ static int gfar_miiphy_read(struct mii_bus *bus, int addr, int reg)
static int gfar_miiphy_write(struct mii_bus *bus, int addr, int reg,
u16 value)
{
- struct device_d *dev = bus->parent;
- struct gfar_private *priv = bus->priv;
+ struct gfar_phy *phy = bus->priv;
unsigned short val = value;
int ret;
- ret = gfar_local_mdio_write(priv->phyregs, addr, reg, val);
+ ret = gfar_local_mdio_write(phy->dev->id, addr, reg, val);
if (ret)
- dev_err(dev, "Can't write PHY at address %d\n", addr);
+ dev_err(phy->dev, "Can't write PHY at address %d\n", addr);
return 0;
}
@@ -481,8 +500,12 @@ static int gfar_probe(struct device_d *dev)
edev = &priv->edev;
priv->regs = dev_request_mem_region(dev, 0);
- priv->phyregs = dev_request_mem_region(dev, 1);
- priv->phyregs_sgmii = dev_request_mem_region(dev, 2);
+ priv->mdiobus = gfar_info->mdiobus;
+ priv->mdiobus_sgmii = gfar_info->mdiobus_sgmii;
+
+ if (priv->mdiobus >= ARRAY_SIZE(phys) ||
+ priv->mdiobus_sgmii >= ARRAY_SIZE(phys))
+ return -EINVAL;
priv->phyaddr = gfar_info->phyaddr;
priv->tbicr = gfar_info->tbicr;
@@ -512,15 +535,8 @@ static int gfar_probe(struct device_d *dev)
udelay(2);
clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
- priv->miibus.read = gfar_miiphy_read;
- priv->miibus.write = gfar_miiphy_write;
- priv->miibus.priv = priv;
- priv->miibus.parent = dev;
-
gfar_init_phy(edev);
- mdiobus_register(&priv->miibus);
-
return eth_register(edev);
}
@@ -529,3 +545,32 @@ static struct driver_d gfar_eth_driver = {
.probe = gfar_probe,
};
device_platform_driver(gfar_eth_driver);
+
+static int gfar_phy_probe(struct device_d *dev)
+{
+ struct gfar_phy *phy;
+ int ret;
+
+ phy = xzalloc(sizeof(*phy));
+ phy->dev = dev;
+ phy->regs = dev_request_mem_region(dev, 0);
+ if (!phy->regs)
+ return -ENOMEM;
+
+ phy->miibus.read = gfar_miiphy_read;
+ phy->miibus.write = gfar_miiphy_write;
+ phy->miibus.priv = phy;
+ phy->miibus.parent = dev;
+
+ ret = mdiobus_register(&phy->miibus);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct driver_d gfar_phy_driver = {
+ .name = "gfar-phy",
+ .probe = gfar_phy_probe,
+};
+register_driver_macro(coredevice, platform, gfar_phy_driver);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index b52cc5a..9094506 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -266,10 +266,9 @@ struct rxbd8 {
struct gfar_private {
struct eth_device edev;
void __iomem *regs;
- void __iomem *phyregs;
- void __iomem *phyregs_sgmii;
+ int mdiobus;
+ int mdiobus_sgmii;
struct phy_info *phyinfo;
- struct mii_bus miibus;
volatile struct txbd8 *txbd;
volatile struct rxbd8 *rxbd;
uint txidx;
--
1.8.2.rc2
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/2] ppc: gianfar MDIO buses
2013-05-30 15:15 [PATCH] gianfar: prevent resource conflict Renaud Barbier
2013-06-01 9:20 ` Sascha Hauer
2013-06-25 13:09 ` [PATCH v2 0/2] " Renaud Barbier
@ 2013-06-25 13:09 ` Renaud Barbier
2013-06-26 6:44 ` Sascha Hauer
2013-06-25 13:10 ` [PATCH 2/2] P2020RDB: update build configuration Renaud Barbier
3 siblings, 1 reply; 10+ messages in thread
From: Renaud Barbier @ 2013-06-25 13:09 UTC (permalink / raw)
To: barebox
This commit creates MDIO bus devices to separate the MDIO bus
abstraction from the Ethernet device initialisation.
It also updates the configuration of the P2020RDB ports.
Signed-off-by: Renaud Barbier <renaud.barbier@ge.com>
---
arch/ppc/boards/freescale-p2020rdb/p2020rdb.c | 13 ++-
arch/ppc/mach-mpc85xx/eth-devices.c | 44 +++++---
arch/ppc/mach-mpc85xx/include/mach/gianfar.h | 4 +
drivers/net/gianfar.c | 146 +++++++++++++++++++------
drivers/net/gianfar.h | 13 ++-
5 files changed, 162 insertions(+), 58 deletions(-)
diff --git a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
index edb9bcd..6426bd3 100644
--- a/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
+++ b/arch/ppc/boards/freescale-p2020rdb/p2020rdb.c
@@ -59,12 +59,19 @@
#define SYSCLK_50 50000000
#define SYSCLK_100 100000000
-/* Ethernet. Use eTSEC3 */
+/* Define attributes for eTSEC2 and eTSEC3 */
static struct gfar_info_struct gfar_info[] = {
{
+ .phyaddr = 0,
+ .tbiana = 0x1a0,
+ .tbicr = 0x9140,
+ .mdiobus_tbi = 1,
+ },
+ {
.phyaddr = 1,
.tbiana = 0,
.tbicr = 0,
+ .mdiobus_tbi = 2,
},
};
@@ -82,8 +89,8 @@ static int devices_init(void)
add_generic_device("i2c-fsl", 1, NULL, I2C2_BASE_ADDR,
0x100, IORESOURCE_MEM, &i2cplat);
- /* eTSEC3 */
- fsl_eth_init(3, &gfar_info[0]);
+ fsl_eth_init(2, &gfar_info[0]);
+ fsl_eth_init(3, &gfar_info[1]);
devfs_add_partition("nor0", 0xf80000, 0x80000, DEVFS_PARTITION_FIXED,
"self0");
diff --git a/arch/ppc/mach-mpc85xx/eth-devices.c b/arch/ppc/mach-mpc85xx/eth-devices.c
index c6e8f36..611a578 100644
--- a/arch/ppc/mach-mpc85xx/eth-devices.c
+++ b/arch/ppc/mach-mpc85xx/eth-devices.c
@@ -22,28 +22,40 @@
#include <common.h>
#include <driver.h>
+#include <init.h>
#include <mach/immap_85xx.h>
#include <mach/gianfar.h>
-int fsl_eth_init(int num, struct gfar_info_struct *gf)
+static int fsl_phy_init(void)
{
- struct resource *res;
+ int i;
+ void __iomem *base = IOMEM(GFAR_BASE_ADDR + GFAR_TBIPA_OFFSET);
+
+ /*
+ * The TBI address must be initialised to enable the PHY to
+ * link up after the MDIO reset.
+ */
+ out_be32(base, GFAR_TBIPA_END);
+ /* All ports access external PHYs via the "gfar-mdio" device */
+ add_generic_device("gfar-mdio", 0, NULL, MDIO_BASE_ADDR,
+ 0x1000, IORESOURCE_MEM, NULL);
- res = xzalloc(3 * sizeof(struct resource));
- /* TSEC interface registers */
- res[0].start = GFAR_BASE_ADDR + ((num - 1) * 0x1000);
- res[0].end = res[0].start + 0x1000 - 1;
- res[0].flags = IORESOURCE_MEM;
- /* External PHY access always through eTSEC1 */
- res[1].start = MDIO_BASE_ADDR;
- res[1].end = res[1].start + 0x1000 - 1;
- res[1].flags = IORESOURCE_MEM;
- /* Access to TBI/RTBI interface. */
- res[2].start = MDIO_BASE_ADDR + ((num - 1) * 0x1000);
- res[2].end = res[2].start + 0x1000 - 1;
- res[2].flags = IORESOURCE_MEM;
+ for (i = 1; i < 3; i++) {
+ out_be32(base + (i * 0x1000), GFAR_TBIPA_END - i);
+ /* Use "gfar-tbiphy" devices to access internal PHY. */
+ add_generic_device("gfar-tbiphy", i, NULL,
+ MDIO_BASE_ADDR + (i * 0x1000),
+ 0x1000, IORESOURCE_MEM, NULL);
+ }
+ return 0;
+}
- add_generic_device_res("gfar", DEVICE_ID_DYNAMIC, res, 3, gf);
+coredevice_initcall(fsl_phy_init);
+int fsl_eth_init(int num, struct gfar_info_struct *gf)
+{
+ add_generic_device("gfar", DEVICE_ID_DYNAMIC, NULL,
+ GFAR_BASE_ADDR + ((num - 1) * 0x1000), 0x1000,
+ IORESOURCE_MEM, gf);
return 0;
}
diff --git a/arch/ppc/mach-mpc85xx/include/mach/gianfar.h b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
index ae31638..6a7b9e9 100644
--- a/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
+++ b/arch/ppc/mach-mpc85xx/include/mach/gianfar.h
@@ -22,10 +22,14 @@
* Platform data for the Motorola Triple Speed Ethernet Controller
*/
+#define GFAR_TBIPA_OFFSET 0x030 /* TBI PHY address */
+#define GFAR_TBIPA_END 0x1f /* Last valid PHY address */
+
struct gfar_info_struct {
unsigned int phyaddr;
unsigned int tbiana;
unsigned int tbicr;
+ unsigned int mdiobus_tbi;
};
int fsl_eth_init(int num, struct gfar_info_struct *gf);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 96055bd..f944c6c 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -184,10 +184,11 @@ static int gfar_open(struct eth_device *edev)
{
int ix;
struct gfar_private *priv = edev->priv;
+ struct gfar_phy *phy = priv->gfar_mdio;
void __iomem *regs = priv->regs;
int ret;
- ret = phy_device_connect(edev, &priv->miibus, priv->phyaddr,
+ ret = phy_device_connect(edev, &phy->miibus, priv->phyaddr,
gfar_adjust_link, 0, PHY_INTERFACE_MODE_NA);
if (ret)
return ret;
@@ -305,44 +306,51 @@ static uint gfar_local_mdio_read(void __iomem *phyregs, uint phyid, uint regnum)
static void gfar_configure_serdes(struct gfar_private *priv)
{
- gfar_local_mdio_write(priv->phyregs_sgmii,
+ struct gfar_phy *phy = priv->gfar_tbi;
+
+ gfar_local_mdio_write(phy->regs,
in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_ANA,
priv->tbiana);
- gfar_local_mdio_write(priv->phyregs_sgmii,
+ gfar_local_mdio_write(phy->regs,
in_be32(priv->regs + GFAR_TBIPA_OFFSET),
GFAR_TBI_TBICON, GFAR_TBICON_CLK_SELECT);
- gfar_local_mdio_write(priv->phyregs_sgmii,
+ gfar_local_mdio_write(phy->regs,
in_be32(priv->regs + GFAR_TBIPA_OFFSET), GFAR_TBI_CR,
priv->tbicr);
}
-/* Reset the internal and external PHYs. */
-static void gfar_init_phy(struct eth_device *dev)
+static int gfar_bus_reset(struct mii_bus *bus)
{
- struct gfar_private *priv = dev->priv;
- void __iomem *regs = priv->regs;
+ struct gfar_phy *phy = bus->priv;
uint64_t start;
- /* Assign a Physical address to the TBI */
- out_be32(regs + GFAR_TBIPA_OFFSET, GFAR_TBIPA_VALUE);
-
/* Reset MII (due to new addresses) */
- out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
- out_be32(priv->phyregs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
+ out_be32(phy->regs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_RESET);
+ out_be32(phy->regs + GFAR_MIIMCFG_OFFSET, GFAR_MIIMCFG_INIT_VALUE);
start = get_time_ns();
while (!is_timeout(start, 10 * MSECOND)) {
- if (!(in_be32(priv->phyregs + GFAR_MIIMMIND_OFFSET) &
+ if (!(in_be32(phy->regs + GFAR_MIIMMIND_OFFSET) &
GFAR_MIIMIND_BUSY))
break;
}
+ return 0;
+}
- gfar_local_mdio_write(priv->phyregs, priv->phyaddr, GFAR_MIIM_CR,
+/* Reset the external PHYs. */
+static void gfar_init_phy(struct eth_device *dev)
+{
+ struct gfar_private *priv = dev->priv;
+ struct gfar_phy *phy = priv->gfar_mdio;
+ void __iomem *regs = priv->regs;
+ uint64_t start;
+
+ gfar_local_mdio_write(phy->regs, priv->phyaddr, GFAR_MIIM_CR,
GFAR_MIIM_CR_RST);
start = get_time_ns();
while (!is_timeout(start, 10 * MSECOND)) {
- if (!(gfar_local_mdio_read(priv->phyregs, priv->phyaddr,
+ if (!(gfar_local_mdio_read(phy->regs, priv->phyaddr,
GFAR_MIIM_CR) & GFAR_MIIM_CR_RST))
break;
}
@@ -433,13 +441,12 @@ static int gfar_recv(struct eth_device *edev)
/* Read a MII PHY register. */
static int gfar_miiphy_read(struct mii_bus *bus, int addr, int reg)
{
- struct device_d *dev = bus->parent;
- struct gfar_private *priv = bus->priv;
+ struct gfar_phy *phy = bus->priv;
int ret;
- ret = gfar_local_mdio_read(priv->phyregs, addr, reg);
+ ret = gfar_local_mdio_read(phy->regs, addr, reg);
if (ret == -EIO)
- dev_err(dev, "Can't read PHY at address %d\n", addr);
+ dev_err(phy->dev, "Can't read PHY at address %d\n", addr);
return ret;
}
@@ -448,15 +455,14 @@ static int gfar_miiphy_read(struct mii_bus *bus, int addr, int reg)
static int gfar_miiphy_write(struct mii_bus *bus, int addr, int reg,
u16 value)
{
- struct device_d *dev = bus->parent;
- struct gfar_private *priv = bus->priv;
+ struct gfar_phy *phy = bus->priv;
unsigned short val = value;
int ret;
- ret = gfar_local_mdio_write(priv->phyregs, addr, reg, val);
+ ret = gfar_local_mdio_write(phy->regs, addr, reg, val);
if (ret)
- dev_err(dev, "Can't write PHY at address %d\n", addr);
+ dev_err(phy->dev, "Can't write PHY at address %d\n", addr);
return 0;
}
@@ -470,7 +476,9 @@ static int gfar_probe(struct device_d *dev)
struct gfar_info_struct *gfar_info = dev->platform_data;
struct eth_device *edev;
struct gfar_private *priv;
+ struct device_d *mdev;
size_t size;
+ char devname[16];
char *p;
priv = xzalloc(sizeof(struct gfar_private));
@@ -480,14 +488,28 @@ static int gfar_probe(struct device_d *dev)
edev = &priv->edev;
- priv->regs = dev_request_mem_region(dev, 0);
- priv->phyregs = dev_request_mem_region(dev, 1);
- priv->phyregs_sgmii = dev_request_mem_region(dev, 2);
-
+ priv->mdiobus_tbi = gfar_info->mdiobus_tbi;
+ priv->regs = dev_get_mem_region(dev, 0);
priv->phyaddr = gfar_info->phyaddr;
priv->tbicr = gfar_info->tbicr;
priv->tbiana = gfar_info->tbiana;
+ mdev = get_device_by_name("gfar-mdio0");
+ if (mdev == NULL) {
+ pr_err("gfar-mdio0 was not found\n");
+ return -ENODEV;
+ }
+ priv->gfar_mdio = mdev->priv;
+
+ if (priv->mdiobus_tbi != 0) {
+ sprintf(devname, "%s%d", "gfar-tbiphy", priv->mdiobus_tbi);
+ mdev = get_device_by_name(devname);
+ if (mdev == NULL) {
+ pr_err("%s was not found\n", devname);
+ return -ENODEV;
+ }
+ }
+ priv->gfar_tbi = mdev->priv;
/*
* Allocate descriptors 64-bit aligned. Descriptors
* are 8 bytes in size.
@@ -512,15 +534,8 @@ static int gfar_probe(struct device_d *dev)
udelay(2);
clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
- priv->miibus.read = gfar_miiphy_read;
- priv->miibus.write = gfar_miiphy_write;
- priv->miibus.priv = priv;
- priv->miibus.parent = dev;
-
gfar_init_phy(edev);
- mdiobus_register(&priv->miibus);
-
return eth_register(edev);
}
@@ -529,3 +544,64 @@ static struct driver_d gfar_eth_driver = {
.probe = gfar_probe,
};
device_platform_driver(gfar_eth_driver);
+
+static int gfar_phy_probe(struct device_d *dev)
+{
+ struct gfar_phy *phy;
+ int ret;
+
+ phy = xzalloc(sizeof(*phy));
+ phy->dev = dev;
+ phy->regs = dev_get_mem_region(dev, 0);
+ if (!phy->regs)
+ return -ENOMEM;
+
+ phy->miibus.read = gfar_miiphy_read;
+ phy->miibus.write = gfar_miiphy_write;
+ phy->miibus.priv = phy;
+ phy->miibus.reset = gfar_bus_reset;
+ phy->miibus.parent = dev;
+ dev->priv = phy;
+
+ ret = mdiobus_register(&phy->miibus);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct driver_d gfar_phy_driver = {
+ .name = "gfar-mdio",
+ .probe = gfar_phy_probe,
+};
+register_driver_macro(coredevice, platform, gfar_phy_driver);
+
+static int gfar_tbiphy_probe(struct device_d *dev)
+{
+ struct gfar_phy *phy;
+ int ret;
+
+ phy = xzalloc(sizeof(*phy));
+ phy->dev = dev;
+ phy->regs = dev_get_mem_region(dev, 0);
+ if (!phy->regs)
+ return -ENOMEM;
+
+ phy->miibus.read = gfar_miiphy_read;
+ phy->miibus.write = gfar_miiphy_write;
+ phy->miibus.priv = phy;
+ phy->miibus.parent = dev;
+ dev->priv = phy;
+
+ ret = mdiobus_register(&phy->miibus);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct driver_d gfar_tbiphy_driver = {
+ .name = "gfar-tbiphy",
+ .probe = gfar_tbiphy_probe,
+};
+register_driver_macro(coredevice, platform, gfar_tbiphy_driver);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index b52cc5a..1aac479 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -205,7 +205,6 @@ struct rxbd8 {
#define GFAR_ECNTRL_OFFSET 0x020 /* Ethernet Control */
#define GFAR_MINFLR_OFFSET 0x024 /* Minimum Frame Length */
#define GFAR_DMACTRL_OFFSET 0x02c /* DMA Control */
-#define GFAR_TBIPA_OFFSET 0x030 /* TBI PHY address */
/* eTSEC transmit control and status register */
#define GFAR_TSTAT_OFFSET 0x104 /* transmit status register */
@@ -263,13 +262,19 @@ struct rxbd8 {
#define GFAR_ATTR_OFFSET 0xbf8 /* Default Attribute Register */
#define GFAR_ATTRELI_OFFSET 0xbfc /* Default Attribute Extract Len/Idx */
+struct gfar_phy {
+ void __iomem *regs;
+ struct device_d *dev;
+ struct mii_bus miibus;
+};
+
struct gfar_private {
struct eth_device edev;
void __iomem *regs;
- void __iomem *phyregs;
- void __iomem *phyregs_sgmii;
+ int mdiobus_tbi;
+ struct gfar_phy *gfar_mdio;
+ struct gfar_phy *gfar_tbi;
struct phy_info *phyinfo;
- struct mii_bus miibus;
volatile struct txbd8 *txbd;
volatile struct rxbd8 *rxbd;
uint txidx;
--
1.7.1
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 10+ messages in thread