131 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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));
 | |
| 		}
 | |
| 	}
 | |
| }
 |