Enable entherent for T1040QDS. It enables FM1@DTSEC3, FM1@DTSEC4, FM1@DTSEC5 Define MDIO related configs Added eth.c file Update t1040.c to support RGMII and SGMII Update t1040qds.c to support ethernet Define the PHY address Signed-off-by: Arpit Goel <B44344@freescale.com> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@freescale.com> Signed-off-by: Poonam Aggrwal <poonam.aggrwal@freescale.com> Signed-off-by: Priyanka Jain <Priyanka.Jain@freescale.com> Signed-off-by: Prabhakar Kushwaha <prabhakar@freescale.com> [York Sun: remove dash from commit message] Signed-off-by: York Sun <yorksun@freescale.com>master
parent
96bda02c9e
commit
5b7672fc49
@ -0,0 +1,492 @@ |
||||
/*
|
||||
* Copyright 2013 Freescale Semiconductor, Inc. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
/*
|
||||
* The RGMII PHYs are provided by the two on-board PHY connected to |
||||
* dTSEC instances 4 and 5. The SGMII PHYs are provided by one on-board |
||||
* PHY or by the standard four-port SGMII riser card (VSC). |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <netdev.h> |
||||
#include <asm/fsl_serdes.h> |
||||
#include <asm/immap_85xx.h> |
||||
#include <fm_eth.h> |
||||
#include <fsl_mdio.h> |
||||
#include <malloc.h> |
||||
#include <asm/fsl_dtsec.h> |
||||
|
||||
#include "../common/fman.h" |
||||
#include "../common/qixis.h" |
||||
|
||||
#include "t1040qds_qixis.h" |
||||
|
||||
#ifdef CONFIG_FMAN_ENET |
||||
/* - In T1040 there are only 8 SERDES lanes, spread across 2 SERDES banks.
|
||||
* Bank 1 -> Lanes A, B, C, D |
||||
* Bank 2 -> Lanes E, F, G, H |
||||
*/ |
||||
|
||||
/* Mapping of 8 SERDES lanes to T1040 QDS board slots. A value of '0' here
|
||||
* means that the mapping must be determined dynamically, or that the lane |
||||
* maps to something other than a board slot. |
||||
*/ |
||||
static u8 lane_to_slot[] = { |
||||
0, 0, 0, 0, 0, 0, 0, 0 |
||||
}; |
||||
|
||||
/* On the Vitesse VSC8234XHG SGMII riser card there are 4 SGMII PHYs
|
||||
* housed. |
||||
*/ |
||||
static int riser_phy_addr[] = { |
||||
CONFIG_SYS_FM1_DTSEC1_RISER_PHY_ADDR, |
||||
CONFIG_SYS_FM1_DTSEC2_RISER_PHY_ADDR, |
||||
CONFIG_SYS_FM1_DTSEC3_RISER_PHY_ADDR, |
||||
CONFIG_SYS_FM1_DTSEC4_RISER_PHY_ADDR, |
||||
}; |
||||
|
||||
/* Slot2 does not have EMI connections */ |
||||
#define EMI_NONE 0xFFFFFFFF |
||||
#define EMI1_RGMII0 0 |
||||
#define EMI1_RGMII1 1 |
||||
#define EMI1_SLOT1 2 |
||||
#define EMI1_SLOT3 3 |
||||
#define EMI1_SLOT4 4 |
||||
#define EMI1_SLOT5 5 |
||||
#define EMI1_SLOT6 6 |
||||
#define EMI1_SLOT7 7 |
||||
#define EMI2 8 |
||||
|
||||
static int mdio_mux[NUM_FM_PORTS]; |
||||
|
||||
static const char * const mdio_names[] = { |
||||
"T1040_QDS_MDIO0", |
||||
"T1040_QDS_MDIO1", |
||||
"T1040_QDS_MDIO2", |
||||
"T1040_QDS_MDIO3", |
||||
"T1040_QDS_MDIO4", |
||||
"T1040_QDS_MDIO5", |
||||
"T1040_QDS_MDIO6", |
||||
"T1040_QDS_MDIO7", |
||||
}; |
||||
|
||||
struct t1040_qds_mdio { |
||||
u8 muxval; |
||||
struct mii_dev *realbus; |
||||
}; |
||||
|
||||
static const char *t1040_qds_mdio_name_for_muxval(u8 muxval) |
||||
{ |
||||
return mdio_names[muxval]; |
||||
} |
||||
|
||||
struct mii_dev *mii_dev_for_muxval(u8 muxval) |
||||
{ |
||||
struct mii_dev *bus; |
||||
const char *name = t1040_qds_mdio_name_for_muxval(muxval); |
||||
|
||||
if (!name) { |
||||
printf("No bus for muxval %x\n", muxval); |
||||
return NULL; |
||||
} |
||||
|
||||
bus = miiphy_get_dev_by_name(name); |
||||
|
||||
if (!bus) { |
||||
printf("No bus by name %s\n", name); |
||||
return NULL; |
||||
} |
||||
|
||||
return bus; |
||||
} |
||||
|
||||
static void t1040_qds_mux_mdio(u8 muxval) |
||||
{ |
||||
u8 brdcfg4; |
||||
if (muxval <= 7) { |
||||
brdcfg4 = QIXIS_READ(brdcfg[4]); |
||||
brdcfg4 &= ~BRDCFG4_EMISEL_MASK; |
||||
brdcfg4 |= (muxval << BRDCFG4_EMISEL_SHIFT); |
||||
QIXIS_WRITE(brdcfg[4], brdcfg4); |
||||
} |
||||
} |
||||
|
||||
static int t1040_qds_mdio_read(struct mii_dev *bus, int addr, int devad, |
||||
int regnum) |
||||
{ |
||||
struct t1040_qds_mdio *priv = bus->priv; |
||||
|
||||
t1040_qds_mux_mdio(priv->muxval); |
||||
|
||||
return priv->realbus->read(priv->realbus, addr, devad, regnum); |
||||
} |
||||
|
||||
static int t1040_qds_mdio_write(struct mii_dev *bus, int addr, int devad, |
||||
int regnum, u16 value) |
||||
{ |
||||
struct t1040_qds_mdio *priv = bus->priv; |
||||
|
||||
t1040_qds_mux_mdio(priv->muxval); |
||||
|
||||
return priv->realbus->write(priv->realbus, addr, devad, regnum, value); |
||||
} |
||||
|
||||
static int t1040_qds_mdio_reset(struct mii_dev *bus) |
||||
{ |
||||
struct t1040_qds_mdio *priv = bus->priv; |
||||
|
||||
return priv->realbus->reset(priv->realbus); |
||||
} |
||||
|
||||
static int t1040_qds_mdio_init(char *realbusname, u8 muxval) |
||||
{ |
||||
struct t1040_qds_mdio *pmdio; |
||||
struct mii_dev *bus = mdio_alloc(); |
||||
|
||||
if (!bus) { |
||||
printf("Failed to allocate t1040_qds MDIO bus\n"); |
||||
return -1; |
||||
} |
||||
|
||||
pmdio = malloc(sizeof(*pmdio)); |
||||
if (!pmdio) { |
||||
printf("Failed to allocate t1040_qds private data\n"); |
||||
free(bus); |
||||
return -1; |
||||
} |
||||
|
||||
bus->read = t1040_qds_mdio_read; |
||||
bus->write = t1040_qds_mdio_write; |
||||
bus->reset = t1040_qds_mdio_reset; |
||||
sprintf(bus->name, t1040_qds_mdio_name_for_muxval(muxval)); |
||||
|
||||
pmdio->realbus = miiphy_get_dev_by_name(realbusname); |
||||
|
||||
if (!pmdio->realbus) { |
||||
printf("No bus with name %s\n", realbusname); |
||||
free(bus); |
||||
free(pmdio); |
||||
return -1; |
||||
} |
||||
|
||||
pmdio->muxval = muxval; |
||||
bus->priv = pmdio; |
||||
|
||||
return mdio_register(bus); |
||||
} |
||||
|
||||
/*
|
||||
* Initialize the lane_to_slot[] array. |
||||
* |
||||
* On the T1040QDS board the mapping is controlled by ?? register. |
||||
*/ |
||||
static void initialize_lane_to_slot(void) |
||||
{ |
||||
ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; |
||||
int serdes1_prtcl = (in_be32(&gur->rcwsr[4]) & |
||||
FSL_CORENET2_RCWSR4_SRDS1_PRTCL) |
||||
>> FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT; |
||||
|
||||
QIXIS_WRITE(cms[0], 0x07); |
||||
|
||||
switch (serdes1_prtcl) { |
||||
case 0x60: |
||||
case 0x66: |
||||
case 0x67: |
||||
case 0x69: |
||||
lane_to_slot[1] = 7; |
||||
lane_to_slot[2] = 6; |
||||
lane_to_slot[3] = 5; |
||||
break; |
||||
case 0x86: |
||||
lane_to_slot[1] = 7; |
||||
lane_to_slot[2] = 7; |
||||
lane_to_slot[3] = 7; |
||||
break; |
||||
case 0x87: |
||||
lane_to_slot[1] = 7; |
||||
lane_to_slot[2] = 7; |
||||
lane_to_slot[3] = 7; |
||||
lane_to_slot[7] = 7; |
||||
break; |
||||
case 0x89: |
||||
lane_to_slot[1] = 7; |
||||
lane_to_slot[2] = 7; |
||||
lane_to_slot[3] = 7; |
||||
lane_to_slot[7] = 7; |
||||
break; |
||||
case 0x8d: |
||||
lane_to_slot[1] = 7; |
||||
lane_to_slot[2] = 7; |
||||
lane_to_slot[3] = 7; |
||||
lane_to_slot[5] = 3; |
||||
lane_to_slot[6] = 3; |
||||
lane_to_slot[7] = 3; |
||||
break; |
||||
case 0x8F: |
||||
case 0x85: |
||||
lane_to_slot[1] = 7; |
||||
lane_to_slot[2] = 6; |
||||
lane_to_slot[3] = 5; |
||||
lane_to_slot[6] = 3; |
||||
lane_to_slot[7] = 3; |
||||
break; |
||||
case 0xA5: |
||||
lane_to_slot[1] = 7; |
||||
lane_to_slot[6] = 3; |
||||
lane_to_slot[7] = 3; |
||||
break; |
||||
case 0xA7: |
||||
lane_to_slot[1] = 7; |
||||
lane_to_slot[7] = 7; |
||||
break; |
||||
case 0xAA: |
||||
lane_to_slot[1] = 7; |
||||
lane_to_slot[6] = 7; |
||||
lane_to_slot[7] = 7; |
||||
break; |
||||
case 0x40: |
||||
lane_to_slot[2] = 7; |
||||
lane_to_slot[3] = 7; |
||||
break; |
||||
default: |
||||
printf("qds: Fman: Unsupported SerDes Protocol 0x%02x\n", |
||||
serdes1_prtcl); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* Given the following ... |
||||
* |
||||
* 1) A pointer to an Fman Ethernet node (as identified by the 'compat' |
||||
* compatible string and 'addr' physical address) |
||||
* |
||||
* 2) An Fman port |
||||
* |
||||
* ... update the phy-handle property of the Ethernet node to point to the |
||||
* right PHY. This assumes that we already know the PHY for each port. |
||||
* |
||||
* The offset of the Fman Ethernet node is also passed in for convenience, but |
||||
* it is not used, and we recalculate the offset anyway. |
||||
* |
||||
* Note that what we call "Fman ports" (enum fm_port) is really an Fman MAC. |
||||
* Inside the Fman, "ports" are things that connect to MACs. We only call them |
||||
* ports in U-Boot because on previous Ethernet devices (e.g. Gianfar), MACs |
||||
* and ports are the same thing. |
||||
* |
||||
*/ |
||||
void board_ft_fman_fixup_port(void *fdt, char *compat, phys_addr_t addr, |
||||
enum fm_port port, int offset) |
||||
{ |
||||
phy_interface_t intf = fm_info_get_enet_if(port); |
||||
char phy[16]; |
||||
|
||||
/* The RGMII PHY is identified by the MAC connected to it */ |
||||
if (intf == PHY_INTERFACE_MODE_RGMII) { |
||||
sprintf(phy, "rgmii_phy%u", port == FM1_DTSEC4 ? 1 : 2); |
||||
fdt_set_phy_handle(fdt, compat, addr, phy); |
||||
} |
||||
|
||||
/* The SGMII PHY is identified by the MAC connected to it */ |
||||
if (intf == PHY_INTERFACE_MODE_SGMII) { |
||||
int lane = serdes_get_first_lane(FSL_SRDS_1, SGMII_FM1_DTSEC1 |
||||
+ port); |
||||
u8 slot; |
||||
if (lane < 0) |
||||
return; |
||||
slot = lane_to_slot[lane]; |
||||
if (slot) { |
||||
/* Slot housing a SGMII riser card */ |
||||
sprintf(phy, "phy_s%x_%02x", slot, |
||||
(fm_info_get_phy_address(port - FM1_DTSEC1)- |
||||
CONFIG_SYS_FM1_DTSEC1_RISER_PHY_ADDR + 1)); |
||||
fdt_set_phy_handle(fdt, compat, addr, phy); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void fdt_fixup_board_enet(void *fdt) |
||||
{ |
||||
int i, lane, idx; |
||||
|
||||
for (i = FM1_DTSEC1; i < FM1_DTSEC1 + CONFIG_SYS_NUM_FM1_DTSEC; i++) { |
||||
idx = i - FM1_DTSEC1; |
||||
switch (fm_info_get_enet_if(i)) { |
||||
case PHY_INTERFACE_MODE_SGMII: |
||||
lane = serdes_get_first_lane(FSL_SRDS_1, |
||||
SGMII_FM1_DTSEC1 + idx); |
||||
if (lane < 0) |
||||
break; |
||||
|
||||
switch (mdio_mux[i]) { |
||||
case EMI1_SLOT3: |
||||
fdt_status_okay_by_alias(fdt, "emi1_slot3"); |
||||
break; |
||||
case EMI1_SLOT5: |
||||
fdt_status_okay_by_alias(fdt, "emi1_slot5"); |
||||
break; |
||||
case EMI1_SLOT6: |
||||
fdt_status_okay_by_alias(fdt, "emi1_slot6"); |
||||
break; |
||||
case EMI1_SLOT7: |
||||
fdt_status_okay_by_alias(fdt, "emi1_slot7"); |
||||
break; |
||||
} |
||||
break; |
||||
case PHY_INTERFACE_MODE_RGMII: |
||||
if (i == FM1_DTSEC4) |
||||
fdt_status_okay_by_alias(fdt, "emi1_rgmii0"); |
||||
|
||||
if (i == FM1_DTSEC5) |
||||
fdt_status_okay_by_alias(fdt, "emi1_rgmii1"); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
#endif /* #ifdef CONFIG_FMAN_ENET */ |
||||
|
||||
static void set_brdcfg9_for_gtx_clk(void) |
||||
{ |
||||
u8 brdcfg9; |
||||
brdcfg9 = QIXIS_READ(brdcfg[9]); |
||||
brdcfg9 |= (1 << 5); |
||||
QIXIS_WRITE(brdcfg[9], brdcfg9); |
||||
} |
||||
|
||||
void t1040_handle_phy_interface_sgmii(int i) |
||||
{ |
||||
int lane, idx, slot; |
||||
idx = i - FM1_DTSEC1; |
||||
lane = serdes_get_first_lane(FSL_SRDS_1, |
||||
SGMII_FM1_DTSEC1 + idx); |
||||
|
||||
if (lane < 0) |
||||
return; |
||||
slot = lane_to_slot[lane]; |
||||
|
||||
switch (slot) { |
||||
case 1: |
||||
mdio_mux[i] = EMI1_SLOT1; |
||||
fm_info_set_mdio(i, mii_dev_for_muxval(mdio_mux[i])); |
||||
break; |
||||
case 3: |
||||
if (FM1_DTSEC4 == i) |
||||
fm_info_set_phy_address(i, riser_phy_addr[0]); |
||||
if (FM1_DTSEC5 == i) |
||||
fm_info_set_phy_address(i, riser_phy_addr[1]); |
||||
|
||||
mdio_mux[i] = EMI1_SLOT3; |
||||
|
||||
fm_info_set_mdio(i, mii_dev_for_muxval(mdio_mux[i])); |
||||
break; |
||||
case 4: |
||||
mdio_mux[i] = EMI1_SLOT4; |
||||
fm_info_set_mdio(i, mii_dev_for_muxval(mdio_mux[i])); |
||||
break; |
||||
case 5: |
||||
/* Slot housing a SGMII riser card? */ |
||||
fm_info_set_phy_address(i, riser_phy_addr[0]); |
||||
mdio_mux[i] = EMI1_SLOT5; |
||||
fm_info_set_mdio(i, mii_dev_for_muxval(mdio_mux[i])); |
||||
break; |
||||
case 6: |
||||
/* Slot housing a SGMII riser card? */ |
||||
fm_info_set_phy_address(i, riser_phy_addr[0]); |
||||
mdio_mux[i] = EMI1_SLOT6; |
||||
fm_info_set_mdio(i, mii_dev_for_muxval(mdio_mux[i])); |
||||
break; |
||||
case 7: |
||||
if (FM1_DTSEC1 == i) |
||||
fm_info_set_phy_address(i, riser_phy_addr[0]); |
||||
if (FM1_DTSEC2 == i) |
||||
fm_info_set_phy_address(i, riser_phy_addr[1]); |
||||
if (FM1_DTSEC3 == i) |
||||
fm_info_set_phy_address(i, riser_phy_addr[2]); |
||||
|
||||
mdio_mux[i] = EMI1_SLOT7; |
||||
fm_info_set_mdio(i, mii_dev_for_muxval(mdio_mux[i])); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
fm_info_set_mdio(i, mii_dev_for_muxval(mdio_mux[i])); |
||||
} |
||||
void t1040_handle_phy_interface_rgmii(int i) |
||||
{ |
||||
fm_info_set_phy_address(i, i == FM1_DTSEC5 ? |
||||
CONFIG_SYS_FM1_DTSEC5_PHY_ADDR : |
||||
CONFIG_SYS_FM1_DTSEC4_PHY_ADDR); |
||||
mdio_mux[i] = (i == FM1_DTSEC5) ? EMI1_RGMII1 : |
||||
EMI1_RGMII0; |
||||
fm_info_set_mdio(i, mii_dev_for_muxval(mdio_mux[i])); |
||||
} |
||||
|
||||
int board_eth_init(bd_t *bis) |
||||
{ |
||||
#ifdef CONFIG_FMAN_ENET |
||||
struct memac_mdio_info memac_mdio_info; |
||||
unsigned int i; |
||||
|
||||
printf("Initializing Fman\n"); |
||||
set_brdcfg9_for_gtx_clk(); |
||||
|
||||
initialize_lane_to_slot(); |
||||
|
||||
/* Initialize the mdio_mux array so we can recognize empty elements */ |
||||
for (i = 0; i < NUM_FM_PORTS; i++) |
||||
mdio_mux[i] = EMI_NONE; |
||||
|
||||
memac_mdio_info.regs = |
||||
(struct memac_mdio_controller *)CONFIG_SYS_FM1_DTSEC_MDIO_ADDR; |
||||
memac_mdio_info.name = DEFAULT_FM_MDIO_NAME; |
||||
|
||||
/* Register the real 1G MDIO bus */ |
||||
fm_memac_mdio_init(bis, &memac_mdio_info); |
||||
|
||||
/* Register the muxing front-ends to the MDIO buses */ |
||||
t1040_qds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_RGMII0); |
||||
t1040_qds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_RGMII1); |
||||
t1040_qds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT1); |
||||
t1040_qds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT3); |
||||
t1040_qds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT4); |
||||
t1040_qds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT5); |
||||
t1040_qds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT6); |
||||
t1040_qds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT7); |
||||
|
||||
/*
|
||||
* Program on board RGMII PHY addresses. If the SGMII Riser |
||||
* card used, we'll override the PHY address later. For any DTSEC that |
||||
* is RGMII, we'll also override its PHY address later. We assume that |
||||
* DTSEC4 and DTSEC5 are used for RGMII. |
||||
*/ |
||||
fm_info_set_phy_address(FM1_DTSEC4, CONFIG_SYS_FM1_DTSEC4_PHY_ADDR); |
||||
fm_info_set_phy_address(FM1_DTSEC5, CONFIG_SYS_FM1_DTSEC5_PHY_ADDR); |
||||
|
||||
for (i = FM1_DTSEC1; i < FM1_DTSEC1 + CONFIG_SYS_NUM_FM1_DTSEC; i++) { |
||||
switch (fm_info_get_enet_if(i)) { |
||||
case PHY_INTERFACE_MODE_QSGMII: |
||||
break; |
||||
case PHY_INTERFACE_MODE_SGMII: |
||||
t1040_handle_phy_interface_sgmii(i); |
||||
break; |
||||
|
||||
case PHY_INTERFACE_MODE_RGMII: |
||||
/* Only DTSEC4 and DTSEC5 can be routed to RGMII */ |
||||
t1040_handle_phy_interface_rgmii(i); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
cpu_eth_init(bis); |
||||
#endif |
||||
|
||||
return pci_eth_init(bis); |
||||
} |
Loading…
Reference in new issue