1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2011 Freescale Semiconductor, Inc. 4 * Author: Mingkai Hu <Mingkai.hu (at) freescale.com> 5 */ 6 7 /* 8 * The RGMII PHYs are provided by the two on-board PHY. The SGMII PHYs 9 * are provided by the three on-board PHY or by the standard Freescale 10 * four-port SGMII riser card. We need to change the phy-handle in the 11 * kernel dts file to point to the correct PHY according to serdes mux 12 * and serdes protocol selection. 13 */ 14 15 #include <common.h> 16 #include <netdev.h> 17 #include <asm/fsl_serdes.h> 18 #include <fm_eth.h> 19 #include <fsl_mdio.h> 20 #include <malloc.h> 21 #include <fsl_dtsec.h> 22 23 #include "cpld.h" 24 #include "../common/fman.h" 25 26 #ifdef CONFIG_FMAN_ENET 27 /* 28 * Mapping of all 18 SERDES lanes to board slots. A value of '0' here means 29 * that the mapping must be determined dynamically, or that the lane maps to 30 * something other than a board slot 31 */ 32 static u8 lane_to_slot[] = { 33 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0 34 }; 35 36 static int riser_phy_addr[] = { 37 CONFIG_SYS_FM1_DTSEC1_RISER_PHY_ADDR, 38 CONFIG_SYS_FM1_DTSEC2_RISER_PHY_ADDR, 39 CONFIG_SYS_FM1_DTSEC3_RISER_PHY_ADDR, 40 CONFIG_SYS_FM1_DTSEC4_RISER_PHY_ADDR, 41 }; 42 43 /* 44 * Initialize the lane_to_slot[] array. 45 * 46 * On the P2040RDB board the mapping is controlled by CPLD register. 47 */ 48 static void initialize_lane_to_slot(void) 49 { 50 u8 mux = CPLD_READ(serdes_mux); 51 52 lane_to_slot[6] = (mux & SERDES_MUX_LANE_6_MASK) ? 0 : 1; 53 lane_to_slot[10] = (mux & SERDES_MUX_LANE_A_MASK) ? 0 : 2; 54 lane_to_slot[12] = (mux & SERDES_MUX_LANE_C_MASK) ? 0 : 2; 55 lane_to_slot[13] = (mux & SERDES_MUX_LANE_D_MASK) ? 0 : 2; 56 } 57 58 /* 59 * Given the following ... 60 * 61 * 1) A pointer to an Fman Ethernet node (as identified by the 'compat' 62 * compatible string and 'addr' physical address) 63 * 64 * 2) An Fman port 65 * 66 * ... update the phy-handle property of the Ethernet node to point to the 67 * right PHY. This assumes that we already know the PHY for each port. 68 * 69 * The offset of the Fman Ethernet node is also passed in for convenience, but 70 * it is not used, and we recalculate the offset anyway. 71 * 72 * Note that what we call "Fman ports" (enum fm_port) is really an Fman MAC. 73 * Inside the Fman, "ports" are things that connect to MACs. We only call them 74 * ports in U-Boot because on previous Ethernet devices (e.g. Gianfar), MACs 75 * and ports are the same thing. 76 * 77 */ 78 void board_ft_fman_fixup_port(void *fdt, char *compat, phys_addr_t addr, 79 enum fm_port port, int offset) 80 { 81 phy_interface_t intf = fm_info_get_enet_if(port); 82 char phy[16]; 83 84 /* The RGMII PHY is identified by the MAC connected to it */ 85 if (intf == PHY_INTERFACE_MODE_RGMII) { 86 sprintf(phy, "phy_rgmii_%u", port == FM1_DTSEC5 ? 0 : 1); 87 fdt_set_phy_handle(fdt, compat, addr, phy); 88 } 89 90 /* The SGMII PHY is identified by the MAC connected to it */ 91 if (intf == PHY_INTERFACE_MODE_SGMII) { 92 int lane = serdes_get_first_lane(SGMII_FM1_DTSEC1 + port); 93 u8 slot; 94 if (lane < 0) 95 return; 96 slot = lane_to_slot[lane]; 97 if (slot) { 98 sprintf(phy, "phy_sgmii_%x", 99 CONFIG_SYS_FM1_DTSEC1_RISER_PHY_ADDR 100 + (port - FM1_DTSEC1)); 101 fdt_set_phy_handle(fdt, compat, addr, phy); 102 } else { 103 sprintf(phy, "phy_sgmii_%x", 104 CONFIG_SYS_FM1_DTSEC1_PHY_ADDR 105 + (port - FM1_DTSEC1)); 106 fdt_set_phy_handle(fdt, compat, addr, phy); 107 } 108 } 109 110 if (intf == PHY_INTERFACE_MODE_XGMII) { 111 /* XAUI */ 112 int lane = serdes_get_first_lane(XAUI_FM1); 113 if (lane >= 0) { 114 /* The XAUI PHY is identified by the slot */ 115 sprintf(phy, "phy_xgmii_%u", lane_to_slot[lane]); 116 fdt_set_phy_handle(fdt, compat, addr, phy); 117 } 118 } 119 } 120 #endif /* #ifdef CONFIG_FMAN_ENET */ 121 122 int board_eth_init(bd_t *bis) 123 { 124 #ifdef CONFIG_FMAN_ENET 125 struct fsl_pq_mdio_info dtsec_mdio_info; 126 struct tgec_mdio_info tgec_mdio_info; 127 unsigned int i, slot; 128 int lane; 129 130 printf("Initializing Fman\n"); 131 132 initialize_lane_to_slot(); 133 134 dtsec_mdio_info.regs = 135 (struct tsec_mii_mng *)CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR; 136 dtsec_mdio_info.name = DEFAULT_FM_MDIO_NAME; 137 138 /* Register the real 1G MDIO bus */ 139 fsl_pq_mdio_init(bis, &dtsec_mdio_info); 140 141 tgec_mdio_info.regs = 142 (struct tgec_mdio_controller *)CONFIG_SYS_FM1_TGEC_MDIO_ADDR; 143 tgec_mdio_info.name = DEFAULT_FM_TGEC_MDIO_NAME; 144 145 /* Register the real 10G MDIO bus */ 146 fm_tgec_mdio_init(bis, &tgec_mdio_info); 147 148 /* 149 * Program the three on-board SGMII PHY addresses. If the SGMII Riser 150 * card used, we'll override the PHY address later. For any DTSEC that 151 * is RGMII, we'll also override its PHY address later. We assume that 152 * DTSEC4 and DTSEC5 are used for RGMII. 153 */ 154 fm_info_set_phy_address(FM1_DTSEC1, CONFIG_SYS_FM1_DTSEC1_PHY_ADDR); 155 fm_info_set_phy_address(FM1_DTSEC2, CONFIG_SYS_FM1_DTSEC2_PHY_ADDR); 156 fm_info_set_phy_address(FM1_DTSEC3, CONFIG_SYS_FM1_DTSEC3_PHY_ADDR); 157 158 for (i = FM1_DTSEC1; i < FM1_DTSEC1 + CONFIG_SYS_NUM_FM1_DTSEC; i++) { 159 int idx = i - FM1_DTSEC1; 160 161 switch (fm_info_get_enet_if(i)) { 162 case PHY_INTERFACE_MODE_SGMII: 163 lane = serdes_get_first_lane(SGMII_FM1_DTSEC1 + idx); 164 if (lane < 0) 165 break; 166 slot = lane_to_slot[lane]; 167 if (slot) 168 fm_info_set_phy_address(i, riser_phy_addr[i]); 169 break; 170 case PHY_INTERFACE_MODE_RGMII: 171 /* Only DTSEC4 and DTSEC5 can be routed to RGMII */ 172 fm_info_set_phy_address(i, i == FM1_DTSEC5 ? 173 CONFIG_SYS_FM1_DTSEC5_PHY_ADDR : 174 CONFIG_SYS_FM1_DTSEC4_PHY_ADDR); 175 break; 176 default: 177 printf("Fman1: DTSEC%u set to unknown interface %i\n", 178 idx + 1, fm_info_get_enet_if(i)); 179 break; 180 } 181 182 fm_info_set_mdio(i, 183 miiphy_get_dev_by_name(DEFAULT_FM_MDIO_NAME)); 184 } 185 186 lane = serdes_get_first_lane(XAUI_FM1); 187 if (lane >= 0) { 188 slot = lane_to_slot[lane]; 189 if (slot) 190 fm_info_set_phy_address(FM1_10GEC1, 191 CONFIG_SYS_FM1_10GEC1_PHY_ADDR); 192 } 193 194 fm_info_set_mdio(FM1_10GEC1, 195 miiphy_get_dev_by_name(DEFAULT_FM_TGEC_MDIO_NAME)); 196 cpu_eth_init(bis); 197 #endif 198 199 return pci_eth_init(bis); 200 } 201