dpaa: Support c45 phys

This commit is contained in:
Sebastian Huber 2017-05-24 08:32:09 +02:00
parent 66e83e0e64
commit 9da83e7886
2 changed files with 110 additions and 71 deletions

View File

@ -80,9 +80,11 @@ typedef enum {
#define SUPPORTED_MII (1U << 8) #define SUPPORTED_MII (1U << 8)
#define SUPPORTED_Pause (1U << 9) #define SUPPORTED_Pause (1U << 9)
#define MII_ADDR_C45 (1 << 30)
struct mdio_bus { struct mdio_bus {
int (*read)(struct mdio_bus *bus, int phy, int reg); int (*read)(struct mdio_bus *bus, int addr, int reg);
int (*write)(struct mdio_bus *bus, int phy, int reg, int val); int (*write)(struct mdio_bus *bus, int addr, int reg, int val);
SLIST_ENTRY(mdio_bus) next; SLIST_ENTRY(mdio_bus) next;
int node; int node;
}; };
@ -91,27 +93,14 @@ struct phy_device {
struct { struct {
struct device dev; struct device dev;
int addr; int addr;
int is_c45;
struct mdio_bus *bus; struct mdio_bus *bus;
} mdio; } mdio;
}; };
static inline int int phy_read(struct phy_device *phy_dev, int reg);
phy_read(struct phy_device *phy_dev, int reg)
{
struct mdio_bus *mdio_dev;
mdio_dev = phy_dev->mdio.bus; int phy_write(struct phy_device *phy_dev, int reg, int val);
return ((*mdio_dev->read)(mdio_dev, phy_dev->mdio.addr, (int)reg));
}
static inline int
phy_write(struct phy_device *phy_dev, int reg, int val)
{
struct mdio_bus *mdio_dev;
mdio_dev = phy_dev->mdio.bus;
return ((*mdio_dev->write)(mdio_dev, phy_dev->mdio.addr, reg, val));
}
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -55,7 +55,35 @@ static struct {
.instances = SLIST_HEAD_INITIALIZER(mdio.instances) .instances = SLIST_HEAD_INITIALIZER(mdio.instances)
}; };
MTX_SYSINIT(mdio_mutex, &mdio.mutex, "FDT MDIO", MTX_DEF); MTX_SYSINIT(mdio_mutex, &mdio.mutex, "MDIO", MTX_DEF);
int
phy_read(struct phy_device *phy_dev, int reg)
{
struct mdio_bus *mdio_dev;
int val;
mdio_dev = phy_dev->mdio.bus;
MDIO_LOCK();
val = (*mdio_dev->read)(mdio_dev, phy_dev->mdio.addr,
reg | phy_dev->mdio.is_c45);
MDIO_UNLOCK();
return (val);
}
int
phy_write(struct phy_device *phy_dev, int reg, int val)
{
struct mdio_bus *mdio_dev;
int err;
mdio_dev = phy_dev->mdio.bus;
MDIO_LOCK();
err = (*mdio_dev->write)(mdio_dev, phy_dev->mdio.addr,
reg | phy_dev->mdio.is_c45, val);
MDIO_UNLOCK();
return (err);
}
static uint64_t static uint64_t
fdt_get_address(const void *fdt, int node) fdt_get_address(const void *fdt, int node)
@ -157,78 +185,92 @@ fman_mdio_wait(volatile struct fman_mdio_regs *regs)
} }
static int static int
fman_mdio_read(struct mdio_bus *base, int phy, int reg) fman_mdio_setup(volatile struct fman_mdio_regs *regs, int addr, int reg,
uint32_t *mdio_ctrl_p)
{
uint32_t mdio_cfg;
uint32_t mdio_ctrl;
uint32_t reg_addr;
int err;
err = fman_mdio_wait(regs);
if (err != 0) {
return (err);
}
mdio_cfg = regs->mdio_cfg;
if ((reg & MII_ADDR_C45) != 0) {
reg_addr = (uint32_t)(reg >> 16);
mdio_cfg |= MDIO_CFG_ENC45;
} else {
reg_addr = (uint32_t)reg;
mdio_cfg &= ~MDIO_CFG_ENC45;
}
regs->mdio_cfg = mdio_cfg;
mdio_ctrl = MDIO_CTRL_PHY_ADDR(addr) | MDIO_CTRL_REG_ADDR(reg_addr);
regs->mdio_ctrl = mdio_ctrl;
if ((reg & MII_ADDR_C45) != 0) {
regs->mdio_addr = (uint32_t)(reg & 0xffff);
err = fman_mdio_wait(regs);
if (err != 0) {
return (err);
}
}
*mdio_ctrl_p = mdio_ctrl;
return (0);
}
static int
fman_mdio_read(struct mdio_bus *base, int addr, int reg)
{ {
struct fman_mdio_bus *fm; struct fman_mdio_bus *fm;
volatile struct fman_mdio_regs *regs; volatile struct fman_mdio_regs *regs;
uint32_t mdio_ctrl;
int val; int val;
int err; int err;
fm = (struct fman_mdio_bus *)base; fm = (struct fman_mdio_bus *)base;
regs = fm->regs; regs = fm->regs;
MDIO_LOCK(); err = fman_mdio_setup(regs, addr, reg, &mdio_ctrl);
if (err != 0) {
err = fman_mdio_wait(regs); return (-1);
if (err == 0) {
uint32_t mdio_cfg;
uint32_t mdio_ctrl;
mdio_cfg = regs->mdio_cfg;
mdio_cfg &= ~MDIO_CFG_ENC45;
regs->mdio_cfg = mdio_cfg;
mdio_ctrl = MDIO_CTRL_PHY_ADDR(phy) | MDIO_CTRL_REG_ADDR(reg);
regs->mdio_ctrl = mdio_ctrl;
mdio_ctrl |= MDIO_CTRL_READ;
regs->mdio_ctrl = mdio_ctrl;
err = fman_mdio_wait(regs);
if (err == 0 && (regs->mdio_cfg & MDIO_CFG_RD_ERR) == 0) {
val = (int)(regs->mdio_data & 0xffff);
} else {
val = 0xffff;
}
} else {
val = 0xffff;
} }
MDIO_UNLOCK(); mdio_ctrl |= MDIO_CTRL_READ;
regs->mdio_ctrl = mdio_ctrl;
err = fman_mdio_wait(regs);
if (err == 0 && (regs->mdio_cfg & MDIO_CFG_RD_ERR) == 0) {
val = (int)(regs->mdio_data & 0xffff);
} else {
val = -1;
}
return (val); return (val);
} }
static int static int
fman_mdio_write(struct mdio_bus *base, int phy, int reg, int val) fman_mdio_write(struct mdio_bus *base, int addr, int reg, int val)
{ {
struct fman_mdio_bus *fm; struct fman_mdio_bus *fm;
volatile struct fman_mdio_regs *regs; volatile struct fman_mdio_regs *regs;
uint32_t mdio_ctrl;
int err; int err;
fm = (struct fman_mdio_bus *)base; fm = (struct fman_mdio_bus *)base;
regs = fm->regs; regs = fm->regs;
MDIO_LOCK(); err = fman_mdio_setup(regs, addr, reg, &mdio_ctrl);
if (err != 0) {
err = fman_mdio_wait(regs); return (0);
if (err == 0) {
uint32_t mdio_cfg;
uint32_t mdio_ctrl;
mdio_cfg = regs->mdio_cfg;
mdio_cfg &= ~MDIO_CFG_ENC45;
regs->mdio_cfg = mdio_cfg;
mdio_ctrl = MDIO_CTRL_PHY_ADDR(phy) | MDIO_CTRL_REG_ADDR(reg);
regs->mdio_ctrl = mdio_ctrl;
regs->mdio_data = (uint32_t)(val & 0xffff);
fman_mdio_wait(regs);
} }
MDIO_UNLOCK(); regs->mdio_data = (uint32_t)(val & 0xffff);
fman_mdio_wait(regs);
return (0); return (0);
} }
@ -290,7 +332,7 @@ find_mdio_bus(const void *fdt, int mdio_node,
} }
static struct phy_device * static struct phy_device *
phy_obtain(const void *fdt, int mdio_node, int phy) phy_obtain(const void *fdt, int is_c45, int mdio_node, int addr)
{ {
struct phy_device *phy_dev; struct phy_device *phy_dev;
int err; int err;
@ -300,7 +342,8 @@ phy_obtain(const void *fdt, int mdio_node, int phy)
return (NULL); return (NULL);
} }
phy_dev->mdio.addr = phy; phy_dev->mdio.addr = addr;
phy_dev->mdio.is_c45 = is_c45;
MDIO_LOCK(); MDIO_LOCK();
err = find_mdio_bus(fdt, mdio_node, phy_dev); err = find_mdio_bus(fdt, mdio_node, phy_dev);
MDIO_UNLOCK(); MDIO_UNLOCK();
@ -317,21 +360,28 @@ struct phy_device *
of_phy_find_device(struct device_node *dn) of_phy_find_device(struct device_node *dn)
{ {
const void *fdt; const void *fdt;
const fdt32_t *phy; const fdt32_t *addr;
int len; int len;
int is_c45;
int mdio_node; int mdio_node;
fdt = bsp_fdt_get(); fdt = bsp_fdt_get();
phy = fdt_getprop(fdt, dn->offset, "reg", &len); addr = fdt_getprop(fdt, dn->offset, "reg", &len);
if (phy == NULL || len != sizeof(*phy)) { if (addr == NULL || len != sizeof(*addr)) {
return (NULL); return (NULL);
} }
if (of_device_is_compatible(dn, "ethernet-phy-ieee802.3-c45")) {
is_c45 = MII_ADDR_C45;
} else {
is_c45 = 0;
}
mdio_node = fdt_parent_offset(fdt, dn->offset); mdio_node = fdt_parent_offset(fdt, dn->offset);
if (mdio_node < 0) { if (mdio_node < 0) {
return (NULL); return (NULL);
} }
return (phy_obtain(fdt, mdio_node, (int)fdt32_to_cpu(*phy))); return (phy_obtain(fdt, is_c45, mdio_node, (int)fdt32_to_cpu(*addr)));
} }