Home | History | Annotate | Download | only in common
      1 /*
      2  * Freescale SGMII Riser Card
      3  *
      4  * This driver supports the SGMII Riser card found on the
      5  * "DS" style of development board from Freescale.
      6  *
      7  * This software may be used and distributed according to the
      8  * terms of the GNU Public License, Version 2, incorporated
      9  * herein by reference.
     10  *
     11  * Copyright 2008 Freescale Semiconductor, Inc.
     12  *
     13  */
     14 
     15 #include <config.h>
     16 #include <common.h>
     17 #include <net.h>
     18 #include <linux/libfdt.h>
     19 #include <tsec.h>
     20 #include <fdt_support.h>
     21 
     22 void fsl_sgmii_riser_init(struct tsec_info_struct *tsec_info, int num)
     23 {
     24 	int i;
     25 
     26 	for (i = 0; i < num; i++)
     27 		if (tsec_info[i].flags & TSEC_SGMII)
     28 			tsec_info[i].phyaddr += SGMII_RISER_PHY_OFFSET;
     29 }
     30 
     31 void fsl_sgmii_riser_fdt_fixup(void *fdt)
     32 {
     33 	struct eth_device *dev;
     34 	int node;
     35 	int mdio_node;
     36 	int i = -1;
     37 	int etsec_num = 0;
     38 
     39 	node = fdt_path_offset(fdt, "/aliases");
     40 	if (node < 0)
     41 		return;
     42 
     43 	while ((dev = eth_get_dev_by_index(++i)) != NULL) {
     44 		struct tsec_private *priv;
     45 		int phy_node;
     46 		int enet_node;
     47 		uint32_t ph;
     48 		char sgmii_phy[16];
     49 		char enet[16];
     50 		const u32 *phyh;
     51 		const char *model;
     52 		const char *path;
     53 
     54 		if (!strstr(dev->name, "eTSEC"))
     55 			continue;
     56 
     57 		priv = dev->priv;
     58 		if (!(priv->flags & TSEC_SGMII)) {
     59 			etsec_num++;
     60 			continue;
     61 		}
     62 
     63 		mdio_node = fdt_node_offset_by_compatible(fdt, -1,
     64 				"fsl,gianfar-mdio");
     65 		if (mdio_node < 0)
     66 			return;
     67 
     68 		sprintf(sgmii_phy, "sgmii-phy@%d", etsec_num);
     69 		phy_node = fdt_subnode_offset(fdt, mdio_node, sgmii_phy);
     70 		if (phy_node > 0) {
     71 			fdt_increase_size(fdt, 32);
     72 			ph = fdt_create_phandle(fdt, phy_node);
     73 			if (!ph)
     74 				continue;
     75 		}
     76 
     77 		sprintf(enet, "ethernet%d", etsec_num++);
     78 		path = fdt_getprop(fdt, node, enet, NULL);
     79 		if (!path) {
     80 			debug("No alias for %s\n", enet);
     81 			continue;
     82 		}
     83 
     84 		enet_node = fdt_path_offset(fdt, path);
     85 		if (enet_node < 0)
     86 			continue;
     87 
     88 		model = fdt_getprop(fdt, enet_node, "model", NULL);
     89 
     90 		/*
     91 		 * We only want to do this to eTSECs.  On some platforms
     92 		 * there are more than one type of gianfar-style ethernet
     93 		 * controller, and as we are creating an implicit connection
     94 		 * between ethernet nodes and eTSEC devices, it is best to
     95 		 * make the connection use as much explicit information
     96 		 * as exists.
     97 		 */
     98 		if (!strstr(model, "TSEC"))
     99 			continue;
    100 
    101 		if (phy_node < 0) {
    102 			/*
    103 			 * This part is only for old device tree without
    104 			 * sgmii_phy nodes. It's kept just for compatible
    105 			 * reason. Soon to be deprecated if all device tree
    106 			 * get updated.
    107 			 */
    108 			phyh = fdt_getprop(fdt, enet_node, "phy-handle", NULL);
    109 			if (!phyh)
    110 				continue;
    111 
    112 			phy_node = fdt_node_offset_by_phandle(fdt,
    113 					fdt32_to_cpu(*phyh));
    114 
    115 			priv = dev->priv;
    116 
    117 			if (priv->flags & TSEC_SGMII)
    118 				fdt_setprop_cell(fdt, phy_node, "reg",
    119 						priv->phyaddr);
    120 		} else {
    121 			fdt_setprop(fdt, enet_node, "phy-handle", &ph,
    122 					sizeof(ph));
    123 			fdt_setprop_string(fdt, enet_node,
    124 					"phy-connection-type",
    125 					phy_string_for_interface(
    126 						PHY_INTERFACE_MODE_SGMII));
    127 		}
    128 	}
    129 }
    130