blob: 23157930101f401f332b3a9e94948a34899de62b [file] [log] [blame]
/*
* Freescale SGMII Riser Card
*
* This driver supports the SGMII Riser card found on the
* "DS" style of development board from Freescale.
*
* This software may be used and distributed according to the
* terms of the GNU Public License, Version 2, incorporated
* herein by reference.
*
* Copyright 2008 Freescale Semiconductor, Inc.
*
*/
#include <config.h>
#include <common.h>
#include <log.h>
#include <net.h>
#include <linux/libfdt.h>
#include <tsec.h>
#include <fdt_support.h>
void fsl_sgmii_riser_init(struct tsec_info_struct *tsec_info, int num)
{
int i;
for (i = 0; i < num; i++)
if (tsec_info[i].flags & TSEC_SGMII)
tsec_info[i].phyaddr += SGMII_RISER_PHY_OFFSET;
}
void fsl_sgmii_riser_fdt_fixup(void *fdt)
{
struct eth_device *dev;
int node;
int mdio_node;
int i = -1;
int etsec_num = 0;
node = fdt_path_offset(fdt, "/aliases");
if (node < 0)
return;
while ((dev = eth_get_dev_by_index(++i)) != NULL) {
struct tsec_private *priv;
int phy_node;
int enet_node;
uint32_t ph;
char sgmii_phy[16];
char enet[16];
const u32 *phyh;
const char *model;
const char *path;
if (!strstr(dev->name, "eTSEC"))
continue;
priv = dev->priv;
if (!(priv->flags & TSEC_SGMII)) {
etsec_num++;
continue;
}
mdio_node = fdt_node_offset_by_compatible(fdt, -1,
"fsl,gianfar-mdio");
if (mdio_node < 0)
return;
sprintf(sgmii_phy, "sgmii-phy@%d", etsec_num);
phy_node = fdt_subnode_offset(fdt, mdio_node, sgmii_phy);
if (phy_node > 0) {
fdt_increase_size(fdt, 32);
ph = fdt_create_phandle(fdt, phy_node);
if (!ph)
continue;
}
sprintf(enet, "ethernet%d", etsec_num++);
path = fdt_getprop(fdt, node, enet, NULL);
if (!path) {
debug("No alias for %s\n", enet);
continue;
}
enet_node = fdt_path_offset(fdt, path);
if (enet_node < 0)
continue;
model = fdt_getprop(fdt, enet_node, "model", NULL);
/*
* We only want to do this to eTSECs. On some platforms
* there are more than one type of gianfar-style ethernet
* controller, and as we are creating an implicit connection
* between ethernet nodes and eTSEC devices, it is best to
* make the connection use as much explicit information
* as exists.
*/
if (!strstr(model, "TSEC"))
continue;
if (phy_node < 0) {
/*
* This part is only for old device tree without
* sgmii_phy nodes. It's kept just for compatible
* reason. Soon to be deprecated if all device tree
* get updated.
*/
phyh = fdt_getprop(fdt, enet_node, "phy-handle", NULL);
if (!phyh)
continue;
phy_node = fdt_node_offset_by_phandle(fdt,
fdt32_to_cpu(*phyh));
priv = dev->priv;
if (priv->flags & TSEC_SGMII)
fdt_setprop_cell(fdt, phy_node, "reg",
priv->phyaddr);
} else {
fdt_setprop(fdt, enet_node, "phy-handle", &ph,
sizeof(ph));
fdt_setprop_string(fdt, enet_node,
"phy-connection-type",
phy_string_for_interface(
PHY_INTERFACE_MODE_SGMII));
}
}
}