mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-16 23:18:51 +09:00
![Tom Rini](/assets/img/avatar_default.png)
When U-Boot started using SPDX tags we were among the early adopters and there weren't a lot of other examples to borrow from. So we picked the area of the file that usually had a full license text and replaced it with an appropriate SPDX-License-Identifier: entry. Since then, the Linux Kernel has adopted SPDX tags and they place it as the very first line in a file (except where shebangs are used, then it's second line) and with slightly different comment styles than us. In part due to community overlap, in part due to better tag visibility and in part for other minor reasons, switch over to that style. This commit changes all instances where we have a single declared license in the tag as both the before and after are identical in tag contents. There's also a few places where I found we did not have a tag and have introduced one. Signed-off-by: Tom Rini <trini@konsulko.com>
481 lines
12 KiB
C
481 lines
12 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright 2009-2011 Freescale Semiconductor, Inc.
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <command.h>
|
|
#include <netdev.h>
|
|
#include <asm/mmu.h>
|
|
#include <asm/processor.h>
|
|
#include <asm/cache.h>
|
|
#include <asm/immap_85xx.h>
|
|
#include <asm/fsl_law.h>
|
|
#include <fsl_ddr_sdram.h>
|
|
#include <asm/fsl_serdes.h>
|
|
#include <asm/fsl_portals.h>
|
|
#include <asm/fsl_liodn.h>
|
|
#include <malloc.h>
|
|
#include <fm_eth.h>
|
|
#include <fsl_mdio.h>
|
|
#include <miiphy.h>
|
|
#include <phy.h>
|
|
|
|
#include "../common/ngpixis.h"
|
|
#include "../common/fman.h"
|
|
#include <fsl_dtsec.h>
|
|
|
|
#define EMI_NONE 0xffffffff
|
|
#define EMI_MASK 0xf0000000
|
|
#define EMI1_RGMII 0x0
|
|
#define EMI1_SLOT3 0x80000000 /* bank1 EFGH */
|
|
#define EMI1_SLOT4 0x40000000 /* bank2 ABCD */
|
|
#define EMI1_SLOT5 0xc0000000 /* bank3 ABCD */
|
|
#define EMI2_SLOT4 0x10000000 /* bank2 ABCD */
|
|
#define EMI2_SLOT5 0x30000000 /* bank3 ABCD */
|
|
#define EMI1_MASK 0xc0000000
|
|
#define EMI2_MASK 0x30000000
|
|
|
|
#define PHY_BASE_ADDR 0x00
|
|
#define PHY_BASE_ADDR_SLOT5 0x10
|
|
|
|
static int mdio_mux[NUM_FM_PORTS];
|
|
|
|
static char *mdio_names[16] = {
|
|
"P4080DS_MDIO0",
|
|
"P4080DS_MDIO1",
|
|
NULL,
|
|
"P4080DS_MDIO3",
|
|
"P4080DS_MDIO4",
|
|
NULL, NULL, NULL,
|
|
"P4080DS_MDIO8",
|
|
NULL, NULL, NULL,
|
|
"P4080DS_MDIO12",
|
|
NULL, NULL, NULL,
|
|
};
|
|
|
|
/*
|
|
* Mapping of all 18 SERDES lanes to 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[] = {
|
|
1, 1, 2, 2, 3, 3, 3, 3, 6, 6, 4, 4, 4, 4, 5, 5, 5, 5
|
|
};
|
|
|
|
static char *p4080ds_mdio_name_for_muxval(u32 muxval)
|
|
{
|
|
return mdio_names[(muxval & EMI_MASK) >> 28];
|
|
}
|
|
|
|
struct mii_dev *mii_dev_for_muxval(u32 muxval)
|
|
{
|
|
struct mii_dev *bus;
|
|
char *name = p4080ds_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;
|
|
}
|
|
|
|
#if defined(CONFIG_SYS_P4080_ERRATUM_SERDES9) && defined(CONFIG_PHY_TERANETICS)
|
|
int board_phy_config(struct phy_device *phydev)
|
|
{
|
|
if (phydev->drv->config)
|
|
phydev->drv->config(phydev);
|
|
if (phydev->drv->uid == PHY_UID_TN2020) {
|
|
unsigned long timeout = 1 * 1000; /* 1 seconds */
|
|
enum srds_prtcl device;
|
|
|
|
/*
|
|
* Wait for the XAUI to come out of reset. This is when it
|
|
* starts transmitting alignment signals.
|
|
*/
|
|
while (--timeout) {
|
|
int reg = phy_read(phydev, MDIO_MMD_PHYXS, MDIO_CTRL1);
|
|
if (reg < 0) {
|
|
printf("TN2020: Error reading from PHY at "
|
|
"address %u\n", phydev->addr);
|
|
break;
|
|
}
|
|
/*
|
|
* Note that we've never actually seen
|
|
* MDIO_CTRL1_RESET set to 1.
|
|
*/
|
|
if ((reg & MDIO_CTRL1_RESET) == 0)
|
|
break;
|
|
udelay(1000);
|
|
}
|
|
|
|
if (!timeout) {
|
|
printf("TN2020: Timeout waiting for PHY at address %u "
|
|
" to reset.\n", phydev->addr);
|
|
}
|
|
|
|
switch (phydev->addr) {
|
|
case CONFIG_SYS_FM1_10GEC1_PHY_ADDR:
|
|
device = XAUI_FM1;
|
|
break;
|
|
case CONFIG_SYS_FM2_10GEC1_PHY_ADDR:
|
|
device = XAUI_FM2;
|
|
break;
|
|
default:
|
|
device = NONE;
|
|
}
|
|
|
|
serdes_reset_rx(device);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
struct p4080ds_mdio {
|
|
u32 muxval;
|
|
struct mii_dev *realbus;
|
|
};
|
|
|
|
static void p4080ds_mux_mdio(u32 muxval)
|
|
{
|
|
ccsr_gpio_t *pgpio = (void *)(CONFIG_SYS_MPC85xx_GPIO_ADDR);
|
|
uint gpioval = in_be32(&pgpio->gpdat) & ~(EMI_MASK);
|
|
gpioval |= muxval;
|
|
|
|
out_be32(&pgpio->gpdat, gpioval);
|
|
}
|
|
|
|
static int p4080ds_mdio_read(struct mii_dev *bus, int addr, int devad,
|
|
int regnum)
|
|
{
|
|
struct p4080ds_mdio *priv = bus->priv;
|
|
|
|
p4080ds_mux_mdio(priv->muxval);
|
|
|
|
return priv->realbus->read(priv->realbus, addr, devad, regnum);
|
|
}
|
|
|
|
static int p4080ds_mdio_write(struct mii_dev *bus, int addr, int devad,
|
|
int regnum, u16 value)
|
|
{
|
|
struct p4080ds_mdio *priv = bus->priv;
|
|
|
|
p4080ds_mux_mdio(priv->muxval);
|
|
|
|
return priv->realbus->write(priv->realbus, addr, devad, regnum, value);
|
|
}
|
|
|
|
static int p4080ds_mdio_reset(struct mii_dev *bus)
|
|
{
|
|
struct p4080ds_mdio *priv = bus->priv;
|
|
|
|
return priv->realbus->reset(priv->realbus);
|
|
}
|
|
|
|
static int p4080ds_mdio_init(char *realbusname, u32 muxval)
|
|
{
|
|
struct p4080ds_mdio *pmdio;
|
|
struct mii_dev *bus = mdio_alloc();
|
|
|
|
if (!bus) {
|
|
printf("Failed to allocate P4080DS MDIO bus\n");
|
|
return -1;
|
|
}
|
|
|
|
pmdio = malloc(sizeof(*pmdio));
|
|
if (!pmdio) {
|
|
printf("Failed to allocate P4080DS private data\n");
|
|
free(bus);
|
|
return -1;
|
|
}
|
|
|
|
bus->read = p4080ds_mdio_read;
|
|
bus->write = p4080ds_mdio_write;
|
|
bus->reset = p4080ds_mdio_reset;
|
|
sprintf(bus->name, p4080ds_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);
|
|
}
|
|
|
|
void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
|
|
enum fm_port port, int offset)
|
|
{
|
|
if (mdio_mux[port] == EMI1_RGMII)
|
|
fdt_set_phy_handle(blob, prop, pa, "phy_rgmii");
|
|
|
|
if (mdio_mux[port] == EMI1_SLOT3) {
|
|
int idx = port - FM2_DTSEC1 + 5;
|
|
char phy[16];
|
|
|
|
sprintf(phy, "phy%d_slot3", idx);
|
|
|
|
fdt_set_phy_handle(blob, prop, pa, phy);
|
|
}
|
|
}
|
|
|
|
void fdt_fixup_board_enet(void *fdt)
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* P4080DS can be configured in many different ways, supporting a number
|
|
* of combinations of ethernet devices and phy types. In order to
|
|
* have just one device tree for all of those configurations, we fix up
|
|
* the tree here. By default, the device tree configures FM1 and FM2
|
|
* for SGMII, and configures XAUI on both 10G interfaces. So we have
|
|
* a number of different variables to track:
|
|
*
|
|
* 1) Whether the device is configured at all. Whichever devices are
|
|
* not enabled should be disabled by setting the "status" property
|
|
* to "disabled".
|
|
* 2) What the PHY interface is. If this is an RGMII connection,
|
|
* we should change the "phy-connection-type" property to
|
|
* "rgmii"
|
|
* 3) Which PHY is being used. Because the MDIO buses are muxed,
|
|
* we need to redirect the "phy-handle" property to point at the
|
|
* PHY on the right slot/bus.
|
|
*/
|
|
|
|
/* We've got six MDIO nodes that may or may not need to exist */
|
|
fdt_status_disabled_by_alias(fdt, "emi1_slot3");
|
|
fdt_status_disabled_by_alias(fdt, "emi1_slot4");
|
|
fdt_status_disabled_by_alias(fdt, "emi1_slot5");
|
|
fdt_status_disabled_by_alias(fdt, "emi2_slot4");
|
|
fdt_status_disabled_by_alias(fdt, "emi2_slot5");
|
|
|
|
for (i = 0; i < NUM_FM_PORTS; i++) {
|
|
switch (mdio_mux[i]) {
|
|
case EMI1_SLOT3:
|
|
fdt_status_okay_by_alias(fdt, "emi1_slot3");
|
|
break;
|
|
case EMI1_SLOT4:
|
|
fdt_status_okay_by_alias(fdt, "emi1_slot4");
|
|
break;
|
|
case EMI1_SLOT5:
|
|
fdt_status_okay_by_alias(fdt, "emi1_slot5");
|
|
break;
|
|
case EMI2_SLOT4:
|
|
fdt_status_okay_by_alias(fdt, "emi2_slot4");
|
|
break;
|
|
case EMI2_SLOT5:
|
|
fdt_status_okay_by_alias(fdt, "emi2_slot5");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int board_eth_init(bd_t *bis)
|
|
{
|
|
#ifdef CONFIG_FMAN_ENET
|
|
ccsr_gpio_t *pgpio = (void *)(CONFIG_SYS_MPC85xx_GPIO_ADDR);
|
|
int i;
|
|
struct fsl_pq_mdio_info dtsec_mdio_info;
|
|
struct tgec_mdio_info tgec_mdio_info;
|
|
struct mii_dev *bus;
|
|
|
|
/* Initialize the mdio_mux array so we can recognize empty elements */
|
|
for (i = 0; i < NUM_FM_PORTS; i++)
|
|
mdio_mux[i] = EMI_NONE;
|
|
|
|
/* The first 4 GPIOs are outputs to control MDIO bus muxing */
|
|
out_be32(&pgpio->gpdir, EMI_MASK);
|
|
|
|
dtsec_mdio_info.regs =
|
|
(struct tsec_mii_mng *)CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR;
|
|
dtsec_mdio_info.name = DEFAULT_FM_MDIO_NAME;
|
|
|
|
/* Register the 1G MDIO bus */
|
|
fsl_pq_mdio_init(bis, &dtsec_mdio_info);
|
|
|
|
tgec_mdio_info.regs =
|
|
(struct tgec_mdio_controller *)CONFIG_SYS_FM1_TGEC_MDIO_ADDR;
|
|
tgec_mdio_info.name = DEFAULT_FM_TGEC_MDIO_NAME;
|
|
|
|
/* Register the 10G MDIO bus */
|
|
fm_tgec_mdio_init(bis, &tgec_mdio_info);
|
|
|
|
/* Register the 6 muxing front-ends to the MDIO buses */
|
|
p4080ds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_RGMII);
|
|
p4080ds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT3);
|
|
p4080ds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT4);
|
|
p4080ds_mdio_init(DEFAULT_FM_MDIO_NAME, EMI1_SLOT5);
|
|
p4080ds_mdio_init(DEFAULT_FM_TGEC_MDIO_NAME, EMI2_SLOT4);
|
|
p4080ds_mdio_init(DEFAULT_FM_TGEC_MDIO_NAME, EMI2_SLOT5);
|
|
|
|
fm_info_set_phy_address(FM1_DTSEC1, CONFIG_SYS_FM1_DTSEC1_PHY_ADDR);
|
|
fm_info_set_phy_address(FM1_DTSEC2, CONFIG_SYS_FM1_DTSEC2_PHY_ADDR);
|
|
fm_info_set_phy_address(FM1_DTSEC3, CONFIG_SYS_FM1_DTSEC3_PHY_ADDR);
|
|
fm_info_set_phy_address(FM1_DTSEC4, CONFIG_SYS_FM1_DTSEC4_PHY_ADDR);
|
|
fm_info_set_phy_address(FM1_10GEC1, CONFIG_SYS_FM1_10GEC1_PHY_ADDR);
|
|
|
|
#if (CONFIG_SYS_NUM_FMAN == 2)
|
|
fm_info_set_phy_address(FM2_DTSEC1, CONFIG_SYS_FM2_DTSEC1_PHY_ADDR);
|
|
fm_info_set_phy_address(FM2_DTSEC2, CONFIG_SYS_FM2_DTSEC2_PHY_ADDR);
|
|
fm_info_set_phy_address(FM2_DTSEC3, CONFIG_SYS_FM2_DTSEC3_PHY_ADDR);
|
|
fm_info_set_phy_address(FM2_DTSEC4, CONFIG_SYS_FM2_DTSEC4_PHY_ADDR);
|
|
fm_info_set_phy_address(FM2_10GEC1, CONFIG_SYS_FM2_10GEC1_PHY_ADDR);
|
|
#endif
|
|
|
|
for (i = FM1_DTSEC1; i < FM1_DTSEC1 + CONFIG_SYS_NUM_FM1_DTSEC; i++) {
|
|
int idx = i - FM1_DTSEC1, lane, slot;
|
|
switch (fm_info_get_enet_if(i)) {
|
|
case PHY_INTERFACE_MODE_SGMII:
|
|
lane = serdes_get_first_lane(SGMII_FM1_DTSEC1 + idx);
|
|
if (lane < 0)
|
|
break;
|
|
slot = lane_to_slot[lane];
|
|
switch (slot) {
|
|
case 3:
|
|
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:
|
|
mdio_mux[i] = EMI1_SLOT5;
|
|
fm_info_set_mdio(i,
|
|
mii_dev_for_muxval(mdio_mux[i]));
|
|
break;
|
|
};
|
|
break;
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
fm_info_set_phy_address(i, 0);
|
|
mdio_mux[i] = EMI1_RGMII;
|
|
fm_info_set_mdio(i,
|
|
mii_dev_for_muxval(mdio_mux[i]));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
bus = mii_dev_for_muxval(EMI1_SLOT5);
|
|
set_sgmii_phy(bus, FM1_DTSEC1,
|
|
CONFIG_SYS_NUM_FM1_DTSEC, PHY_BASE_ADDR_SLOT5);
|
|
|
|
for (i = FM1_10GEC1; i < FM1_10GEC1 + CONFIG_SYS_NUM_FM1_10GEC; i++) {
|
|
int idx = i - FM1_10GEC1, lane, slot;
|
|
switch (fm_info_get_enet_if(i)) {
|
|
case PHY_INTERFACE_MODE_XGMII:
|
|
lane = serdes_get_first_lane(XAUI_FM1 + idx);
|
|
if (lane < 0)
|
|
break;
|
|
slot = lane_to_slot[lane];
|
|
switch (slot) {
|
|
case 4:
|
|
mdio_mux[i] = EMI2_SLOT4;
|
|
fm_info_set_mdio(i,
|
|
mii_dev_for_muxval(mdio_mux[i]));
|
|
break;
|
|
case 5:
|
|
mdio_mux[i] = EMI2_SLOT5;
|
|
fm_info_set_mdio(i,
|
|
mii_dev_for_muxval(mdio_mux[i]));
|
|
break;
|
|
};
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#if (CONFIG_SYS_NUM_FMAN == 2)
|
|
for (i = FM2_DTSEC1; i < FM2_DTSEC1 + CONFIG_SYS_NUM_FM2_DTSEC; i++) {
|
|
int idx = i - FM2_DTSEC1, lane, slot;
|
|
switch (fm_info_get_enet_if(i)) {
|
|
case PHY_INTERFACE_MODE_SGMII:
|
|
lane = serdes_get_first_lane(SGMII_FM2_DTSEC1 + idx);
|
|
if (lane < 0)
|
|
break;
|
|
slot = lane_to_slot[lane];
|
|
switch (slot) {
|
|
case 3:
|
|
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:
|
|
mdio_mux[i] = EMI1_SLOT5;
|
|
fm_info_set_mdio(i,
|
|
mii_dev_for_muxval(mdio_mux[i]));
|
|
break;
|
|
};
|
|
break;
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
fm_info_set_phy_address(i, 0);
|
|
mdio_mux[i] = EMI1_RGMII;
|
|
fm_info_set_mdio(i,
|
|
mii_dev_for_muxval(mdio_mux[i]));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bus = mii_dev_for_muxval(EMI1_SLOT3);
|
|
set_sgmii_phy(bus, FM2_DTSEC1, CONFIG_SYS_NUM_FM2_DTSEC, PHY_BASE_ADDR);
|
|
bus = mii_dev_for_muxval(EMI1_SLOT4);
|
|
set_sgmii_phy(bus, FM2_DTSEC1, CONFIG_SYS_NUM_FM2_DTSEC, PHY_BASE_ADDR);
|
|
|
|
for (i = FM2_10GEC1; i < FM2_10GEC1 + CONFIG_SYS_NUM_FM2_10GEC; i++) {
|
|
int idx = i - FM2_10GEC1, lane, slot;
|
|
switch (fm_info_get_enet_if(i)) {
|
|
case PHY_INTERFACE_MODE_XGMII:
|
|
lane = serdes_get_first_lane(XAUI_FM2 + idx);
|
|
if (lane < 0)
|
|
break;
|
|
slot = lane_to_slot[lane];
|
|
switch (slot) {
|
|
case 4:
|
|
mdio_mux[i] = EMI2_SLOT4;
|
|
fm_info_set_mdio(i,
|
|
mii_dev_for_muxval(mdio_mux[i]));
|
|
break;
|
|
case 5:
|
|
mdio_mux[i] = EMI2_SLOT5;
|
|
fm_info_set_mdio(i,
|
|
mii_dev_for_muxval(mdio_mux[i]));
|
|
break;
|
|
};
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
cpu_eth_init(bis);
|
|
#endif /* CONFIG_FMAN_ENET */
|
|
|
|
return pci_eth_init(bis);
|
|
}
|