
On Mon, Oct 9, 2017 at 4:11 AM, Calvin Johnson calvin.johnson@nxp.com wrote:
This patch adds PFE driver into U-Boot.
Following are the main driver files:- pfe.c: provides low level helper functions to initialize PFE internal processor engines and other hardware blocks. pfe_driver.c: provides probe functions, initialization functions and packet send and receive functions. pfe_eth.c: provides high level gemac, phy and mdio initialization functions. pfe_firmware.c: provides functions to load firmware into PFE internal processor engines.
Signed-off-by: Calvin Johnson calvin.johnson@nxp.com Signed-off-by: Anjaneyulu Jagarlmudi anji.jagarlmudi@nxp.com
drivers/net/pfe_eth/Kconfig | 8 + drivers/net/pfe_eth/Makefile | 10 + drivers/net/pfe_eth/pfe.c | 1161 ++++++++++++++++++++++++++++++++++++ drivers/net/pfe_eth/pfe_driver.c | 626 +++++++++++++++++++ drivers/net/pfe_eth/pfe_eth.c | 545 +++++++++++++++++ drivers/net/pfe_eth/pfe_firmware.c | 230 +++++++ 6 files changed, 2580 insertions(+) create mode 100644 drivers/net/pfe_eth/Kconfig create mode 100644 drivers/net/pfe_eth/Makefile create mode 100644 drivers/net/pfe_eth/pfe.c create mode 100644 drivers/net/pfe_eth/pfe_driver.c create mode 100644 drivers/net/pfe_eth/pfe_eth.c create mode 100644 drivers/net/pfe_eth/pfe_firmware.c
diff --git a/drivers/net/pfe_eth/Kconfig b/drivers/net/pfe_eth/Kconfig new file mode 100644 index 0000000..b9996df --- /dev/null +++ b/drivers/net/pfe_eth/Kconfig @@ -0,0 +1,8 @@ +config UTIL_PE_DISABLED
bool
help
Disable UTIL processor engine of PFE
+config SYS_FSL_PPFE_ADDR
hex "PFE base address"
default 0x04000000
diff --git a/drivers/net/pfe_eth/Makefile b/drivers/net/pfe_eth/Makefile new file mode 100644 index 0000000..e78f1bf --- /dev/null +++ b/drivers/net/pfe_eth/Makefile @@ -0,0 +1,10 @@ +# Copyright 2015-2016 Freescale Semiconductor, Inc. +# Copyright 2017 NXP +# +# SPDX-License-Identifier:GPL-2.0+
+# Layerscape PFE driver +obj-y += pfe.o \
pfe_driver.o \
pfe_eth.o \
pfe_firmware.o
diff --git a/drivers/net/pfe_eth/pfe.c b/drivers/net/pfe_eth/pfe.c new file mode 100644 index 0000000..fc6631e --- /dev/null +++ b/drivers/net/pfe_eth/pfe.c @@ -0,0 +1,1161 @@ +/*
- Copyright 2015-2016 Freescale Semiconductor, Inc.
- Copyright 2017 NXP
- SPDX-License-Identifier:GPL-2.0+
- */
+#include <pfe_eth/pfe_eth.h> +#include <pfe_eth/pfe/pfe.h>
+void *ddr_base_addr; +unsigned long ddr_phys_base_addr; +static struct pe_info pe[MAX_PE];
+/*
- Initializes the PFE library.
- Must be called before using any of the library functions.
- @param[in] cbus_base CBUS virtual base address (as mapped in
the host CPU address space)
- @param[in] ddr_base DDR virtual base address (as mapped in
the host CPU address space)
- @param[in] ddr_phys_base DDR physical base address (as mapped in
platform)
- */
+void pfe_lib_init(void *ddr_base, unsigned long ddr_phys_base)
Could you use some loops here to consolidate this code some?
+{
ddr_base_addr = ddr_base;
ddr_phys_base_addr = ddr_phys_base;
pe[CLASS0_ID].dmem_base_addr = (u32)CLASS_DMEM_BASE_ADDR(0);
pe[CLASS0_ID].pmem_base_addr = (u32)CLASS_IMEM_BASE_ADDR(0);
pe[CLASS0_ID].pmem_size = (u32)CLASS_IMEM_SIZE;
pe[CLASS0_ID].mem_access_wdata = (void *)CLASS_MEM_ACCESS_WDATA;
pe[CLASS0_ID].mem_access_addr = (void *)CLASS_MEM_ACCESS_ADDR;
pe[CLASS0_ID].mem_access_rdata = (void *)CLASS_MEM_ACCESS_RDATA;
pe[CLASS1_ID].dmem_base_addr = (u32)CLASS_DMEM_BASE_ADDR(1);
pe[CLASS1_ID].pmem_base_addr = (u32)CLASS_IMEM_BASE_ADDR(1);
pe[CLASS1_ID].pmem_size = (u32)CLASS_IMEM_SIZE;
pe[CLASS1_ID].mem_access_wdata = (void *)CLASS_MEM_ACCESS_WDATA;
pe[CLASS1_ID].mem_access_addr = (void *)CLASS_MEM_ACCESS_ADDR;
pe[CLASS1_ID].mem_access_rdata = (void *)CLASS_MEM_ACCESS_RDATA;
pe[CLASS2_ID].dmem_base_addr = (u32)CLASS_DMEM_BASE_ADDR(2);
pe[CLASS2_ID].pmem_base_addr = (u32)CLASS_IMEM_BASE_ADDR(2);
pe[CLASS2_ID].pmem_size = (u32)CLASS_IMEM_SIZE;
pe[CLASS2_ID].mem_access_wdata = (void *)CLASS_MEM_ACCESS_WDATA;
pe[CLASS2_ID].mem_access_addr = (void *)CLASS_MEM_ACCESS_ADDR;
pe[CLASS2_ID].mem_access_rdata = (void *)CLASS_MEM_ACCESS_RDATA;
pe[CLASS3_ID].dmem_base_addr = (u32)CLASS_DMEM_BASE_ADDR(3);
pe[CLASS3_ID].pmem_base_addr = (u32)CLASS_IMEM_BASE_ADDR(3);
pe[CLASS3_ID].pmem_size = (u32)CLASS_IMEM_SIZE;
pe[CLASS3_ID].mem_access_wdata = (void *)CLASS_MEM_ACCESS_WDATA;
pe[CLASS3_ID].mem_access_addr = (void *)CLASS_MEM_ACCESS_ADDR;
pe[CLASS3_ID].mem_access_rdata = (void *)CLASS_MEM_ACCESS_RDATA;
pe[CLASS4_ID].dmem_base_addr = (u32)CLASS_DMEM_BASE_ADDR(4);
pe[CLASS4_ID].pmem_base_addr = (u32)CLASS_IMEM_BASE_ADDR(4);
pe[CLASS4_ID].pmem_size = (u32)CLASS_IMEM_SIZE;
pe[CLASS4_ID].mem_access_wdata = (void *)CLASS_MEM_ACCESS_WDATA;
pe[CLASS4_ID].mem_access_addr = (void *)CLASS_MEM_ACCESS_ADDR;
pe[CLASS4_ID].mem_access_rdata = (void *)CLASS_MEM_ACCESS_RDATA;
pe[CLASS5_ID].dmem_base_addr = (u32)CLASS_DMEM_BASE_ADDR(5);
pe[CLASS5_ID].pmem_base_addr = (u32)CLASS_IMEM_BASE_ADDR(5);
pe[CLASS5_ID].pmem_size = (u32)CLASS_IMEM_SIZE;
pe[CLASS5_ID].mem_access_wdata = (void *)CLASS_MEM_ACCESS_WDATA;
pe[CLASS5_ID].mem_access_addr = (void *)CLASS_MEM_ACCESS_ADDR;
pe[CLASS5_ID].mem_access_rdata = (void *)CLASS_MEM_ACCESS_RDATA;
pe[TMU0_ID].dmem_base_addr = (u32)TMU_DMEM_BASE_ADDR(0);
pe[TMU0_ID].pmem_base_addr = (u32)TMU_IMEM_BASE_ADDR(0);
pe[TMU0_ID].pmem_size = (u32)TMU_IMEM_SIZE;
pe[TMU0_ID].mem_access_wdata = (void *)TMU_MEM_ACCESS_WDATA;
pe[TMU0_ID].mem_access_addr = (void *)TMU_MEM_ACCESS_ADDR;
pe[TMU0_ID].mem_access_rdata = (void *)TMU_MEM_ACCESS_RDATA;
pe[TMU1_ID].dmem_base_addr = (u32)TMU_DMEM_BASE_ADDR(1);
pe[TMU1_ID].pmem_base_addr = (u32)TMU_IMEM_BASE_ADDR(1);
pe[TMU1_ID].pmem_size = (u32)TMU_IMEM_SIZE;
pe[TMU1_ID].mem_access_wdata = (void *)TMU_MEM_ACCESS_WDATA;
pe[TMU1_ID].mem_access_addr = (void *)TMU_MEM_ACCESS_ADDR;
pe[TMU1_ID].mem_access_rdata = (void *)TMU_MEM_ACCESS_RDATA;
pe[TMU3_ID].dmem_base_addr = (u32)TMU_DMEM_BASE_ADDR(3);
pe[TMU3_ID].pmem_base_addr = (u32)TMU_IMEM_BASE_ADDR(3);
pe[TMU3_ID].pmem_size = (u32)TMU_IMEM_SIZE;
pe[TMU3_ID].mem_access_wdata = (void *)TMU_MEM_ACCESS_WDATA;
pe[TMU3_ID].mem_access_addr = (void *)TMU_MEM_ACCESS_ADDR;
pe[TMU3_ID].mem_access_rdata = (void *)TMU_MEM_ACCESS_RDATA;
+#if !defined(CONFIG_UTIL_PE_DISABLED)
pe[UTIL_ID].dmem_base_addr = (u32)UTIL_DMEM_BASE_ADDR;
pe[UTIL_ID].mem_access_wdata = (void *)UTIL_MEM_ACCESS_WDATA;
pe[UTIL_ID].mem_access_addr = (void *)UTIL_MEM_ACCESS_ADDR;
pe[UTIL_ID].mem_access_rdata = (void *)UTIL_MEM_ACCESS_RDATA;
+#endif +}
[ ... ]
diff --git a/drivers/net/pfe_eth/pfe_driver.c b/drivers/net/pfe_eth/pfe_driver.c new file mode 100644 index 0000000..5336ba7 --- /dev/null +++ b/drivers/net/pfe_eth/pfe_driver.c @@ -0,0 +1,626 @@ +/*
- Copyright 2015-2016 Freescale Semiconductor, Inc.
- Copyright 2017 NXP
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <pfe_eth/pfe_eth.h> +#include <pfe_eth/pfe_firmware.h>
+static struct tx_desc_s *g_tx_desc; +static struct rx_desc_s *g_rx_desc;
+/*
- HIF Rx interface function
- Reads the rx descriptor from the current location (rx_to_read).
- If the descriptor has a valid data/pkt, then get the data pointer
- check for the input rx phy number
- increments the rx data pointer by pkt_head_room_size
- decrements the data length by pkt_head_room_size
- handover the packet to caller.
- @param[out] pkt_ptr Pointer to store rx packet pointer
- @param[out] phy_port Pointer to store recv phy port
- @return -1 if no packet, else returns length of packet.
- */
+int pfe_recv(unsigned int *pkt_ptr, int *phy_port) +{
struct rx_desc_s *rx_desc = g_rx_desc;
struct buf_desc *bd;
int len = -1;
struct hif_header_s *hif_header;
bd = rx_desc->rx_base + rx_desc->rx_to_read;
if (bd->ctrl & BD_CTRL_DESC_EN)
return len; /* No pending Rx packet */
/* this len include hif_header(8bytes) */
len = bd->ctrl & 0xFFFF;
hif_header = (struct hif_header_s *)DDR_PFE_TO_VIRT(bd->data);
/* Get the recive port info from the packet */
Typo: receive
debug(
"Pkt recv'd: Pkt ptr(%p), len(%d), gemac_port(%d) status(%08x)\n",
hif_header, len, hif_header->port_no, bd->status);
+#ifdef DEBUG
{
int i;
unsigned char *p = (unsigned char *)hif_header;
for (i = 0; i < len; i++) {
if (!(i % 16))
printf("\n");
printf(" %02x", p[i]);
}
printf("\n");
}
+#endif
*pkt_ptr = (unsigned long)(hif_header + 1);
*phy_port = hif_header->port_no;
len -= sizeof(struct hif_header_s);
rx_desc->rx_to_read = (rx_desc->rx_to_read + 1)
& (rx_desc->rx_ring_size - 1);
/* reset bd control field */
bd->ctrl = (MAX_FRAME_SIZE | BD_CTRL_LIFM | BD_CTRL_DESC_EN
| BD_CTRL_DIR);
bd->status = 0;
/* Give START_STROBE to BDP to fetch the descriptor __NOW__,
* BDP need not to wait for rx_poll_cycle time to fetch the descriptor,
* In idle state (ie., no rx pkt), BDP will not fetch
* the descriptor even if strobe is given(I think)
*/
writel((readl(HIF_RX_CTRL) | HIF_CTRL_BDP_CH_START_WSTB), HIF_RX_CTRL);
return len;
+}
[ ... ]
diff --git a/drivers/net/pfe_eth/pfe_eth.c b/drivers/net/pfe_eth/pfe_eth.c new file mode 100644 index 0000000..8d8de40 --- /dev/null +++ b/drivers/net/pfe_eth/pfe_eth.c @@ -0,0 +1,545 @@ +/*
- Copyright 2015-2016 Freescale Semiconductor, Inc.
- Copyright 2017 NXP
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <pfe_eth/pfe_eth.h>
+struct gemac_s gem_info[] = {
/* PORT_0 configuration */ {
/* GEMAC config */
.gemac_mode = GMII,
.gemac_speed = SPEED_1000M,
.gemac_duplex = DUPLEX_FULL,
/* phy iface */
.phy_address = EMAC1_PHY_ADDR,
.phy_mode = PHY_INTERFACE_MODE_SGMII,
},
/* PORT_1 configuration */ {
/* GEMAC config */
.gemac_mode = GMII,
.gemac_speed = SPEED_1000M,
.gemac_duplex = DUPLEX_FULL,
/* phy iface */
.phy_address = EMAC2_PHY_ADDR,
.phy_mode = PHY_INTERFACE_MODE_RGMII,
},
+};
+#define MAX_GEMACS 2
+static struct ls1012a_eth_dev *gemac_list[MAX_GEMACS];
+#define MDIO_TIMEOUT 5000
+static inline void ls1012a_gemac_enable(void *gemac_base) +{
writel(readl(gemac_base + EMAC_ECNTRL_REG) |
EMAC_ECNTRL_ETHER_EN, gemac_base + EMAC_ECNTRL_REG);
+}
+static inline void ls1012a_gemac_disable(void *gemac_base) +{
writel(readl(gemac_base + EMAC_ECNTRL_REG) &
~EMAC_ECNTRL_ETHER_EN, gemac_base + EMAC_ECNTRL_REG);
+}
+static inline void ls1012a_gemac_set_speed(void *gemac_base, u32 speed) +{
struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
u32 ecr = readl(gemac_base + EMAC_ECNTRL_REG) & ~EMAC_ECNTRL_SPEED;
u32 rcr = readl(gemac_base + EMAC_RCNTRL_REG) & ~EMAC_RCNTRL_RMII_10T;
u32 rgmii_pcr = in_be32(&scfg->rgmiipcr) &
~(SCFG_RGMIIPCR_SETSP_1000M|SCFG_RGMIIPCR_SETSP_10M);
if (speed == _1000BASET) {
ecr |= EMAC_ECNTRL_SPEED;
rgmii_pcr |= SCFG_RGMIIPCR_SETSP_1000M;
} else if (speed != _100BASET) {
rcr |= EMAC_RCNTRL_RMII_10T;
rgmii_pcr |= SCFG_RGMIIPCR_SETSP_10M;
}
writel(ecr, gemac_base + EMAC_ECNTRL_REG);
out_be32(&scfg->rgmiipcr, rgmii_pcr | SCFG_RGMIIPCR_SETFD);
/* remove loop back */
rcr &= ~EMAC_RCNTRL_LOOP;
/* enable flow control */
rcr |= EMAC_RCNTRL_FCE;
/* Enable MII mode */
rcr |= EMAC_RCNTRL_MII_MODE;
writel(rcr, gemac_base + EMAC_RCNTRL_REG);
/* Enable Tx full duplex */
writel(readl(gemac_base + EMAC_TCNTRL_REG) | EMAC_TCNTRL_FDEN,
gemac_base + EMAC_TCNTRL_REG);
+}
+static inline void ls1012a_gemac_set_ethaddr(void *gemac_base, uchar *mac) +{
writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3],
gemac_base + EMAC_PHY_ADDR_LOW);
writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, gemac_base +
EMAC_PHY_ADDR_HIGH);
+}
+/** Stops or Disables GEMAC pointing to this eth iface.
- @param[in] edev Pointer to eth device structure.
- @return none
- */
+static inline void ls1012a_eth_halt(struct eth_device *edev) +{
struct ls1012a_eth_dev *priv = (struct ls1012a_eth_dev *)edev->priv;
ls1012a_gemac_disable(priv->gem->gemac_base);
gpi_disable(priv->gem->egpi_base);
+}
+static int ls1012a_eth_init(struct eth_device *dev, bd_t *bd) +{
struct ls1012a_eth_dev *priv = (struct ls1012a_eth_dev *)dev->priv;
struct gemac_s *gem = priv->gem;
int speed;
/* set ethernet mac address */
ls1012a_gemac_set_ethaddr(gem->gemac_base, dev->enetaddr);
writel(0x00000004, gem->gemac_base + EMAC_TFWR_STR_FWD);
writel(0x00000005, gem->gemac_base + EMAC_RX_SECTIOM_FULL);
writel(0x00003fff, gem->gemac_base + EMAC_TRUNC_FL);
writel(0x00000030, gem->gemac_base + EMAC_TX_SECTION_EMPTY);
writel(0x00000000, gem->gemac_base + EMAC_MIB_CTRL_STS_REG);
Why all the magic numbers?
+#ifdef CONFIG_PHYLIB
/* Start up the PHY */
if (phy_startup(priv->phydev)) {
printf("Could not initialize PHY %s\n",
priv->phydev->dev->name);
return -1;
}
speed = priv->phydev->speed;
printf("Speed detected %x\n", speed);
if (priv->phydev->duplex == DUPLEX_HALF) {
printf("Half duplex not supported\n");
return -1;
}
+#endif
ls1012a_gemac_set_speed(gem->gemac_base, speed);
/* Enable GPI */
gpi_enable(gem->egpi_base);
/* Enable GEMAC */
ls1012a_gemac_enable(gem->gemac_base);
return 0;
+}
+static int ls1012a_eth_send(struct eth_device *dev, void *data, int length) +{
struct ls1012a_eth_dev *priv = (struct ls1012a_eth_dev *)dev->priv;
int rc;
int i = 0;
rc = pfe_send(priv->gemac_port, data, length);
if (rc < 0) {
printf("Tx Q full\n");
return 0;
}
while (1) {
rc = pfe_tx_done();
if (rc == 0)
break;
udelay(100);
i++;
if (i == 30000)
printf("Tx timeout, send failed\n");
break;
}
return 0;
+}
+static int ls1012a_eth_recv(struct eth_device *dev) +{
struct ls1012a_eth_dev *priv = (struct ls1012a_eth_dev *)dev->priv;
u32 pkt_buf;
int len;
int phy_port;
len = pfe_recv(&pkt_buf, &phy_port);
if (len < 0)
return 0; /* no packet in rx */
debug("Rx pkt: pkt_buf(%08x), phy_port(%d), len(%d)\n", pkt_buf,
phy_port, len);
if (phy_port != priv->gemac_port) {
printf("Rx pkt not on expected port\n");
return 0;
}
/* Pass the packet up to the protocol layers. */
net_process_received_packet((void *)(long int)pkt_buf, len);
Please don't call this directly. The layer above will call it for you if you return the size of the packet that is valid (assuming driver model, see below).
return 0;
+}
+#if defined(CONFIG_PHYLIB)
+#define MDIO_TIMEOUT 5000 +static int ls1012a_write_addr(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr)
+{
void *reg_base = bus->priv;
u32 devadr;
u32 phy;
u32 reg_data;
int timeout = MDIO_TIMEOUT;
devadr = ((dev_addr & EMAC_MII_DATA_RA_MASK) << EMAC_MII_DATA_RA_SHIFT);
phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
reg_data = (EMAC_MII_DATA_TA | phy | devadr | reg_addr);
writel(reg_data, reg_base + EMAC_MII_DATA_REG);
/*
* wait for the MII interrupt
*/
while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
if (timeout-- <= 0) {
printf("Phy MDIO read/write timeout\n");
return -1;
}
}
/*
* clear MII interrupt
*/
writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
return 0;
+}
+static int ls1012a_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr, int
reg_addr)
+{
void *reg_base = bus->priv;
u32 reg;
u32 phy;
u32 reg_data;
u16 val;
int timeout = MDIO_TIMEOUT;
if (dev_addr == MDIO_DEVAD_NONE) {
reg = ((reg_addr & EMAC_MII_DATA_RA_MASK) <<
EMAC_MII_DATA_RA_SHIFT);
} else {
ls1012a_write_addr(bus, phy_addr, dev_addr, reg_addr);
reg = ((dev_addr & EMAC_MII_DATA_RA_MASK) <<
EMAC_MII_DATA_RA_SHIFT);
}
phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
if (dev_addr == MDIO_DEVAD_NONE)
reg_data = (EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_RD |
EMAC_MII_DATA_TA | phy | reg);
else
reg_data = (EMAC_MII_DATA_OP_CL45_RD | EMAC_MII_DATA_TA |
phy | reg);
writel(reg_data, reg_base + EMAC_MII_DATA_REG);
/*
* wait for the MII interrupt
*/
while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
if (timeout-- <= 0) {
printf("Phy MDIO read/write timeout\n");
return -1;
}
}
/*
* clear MII interrupt
*/
writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
/*
* it's now safe to read the PHY's register
*/
val = (u16)readl(reg_base + EMAC_MII_DATA_REG);
debug("%s: %p phy: 0x%x reg:0x%08x val:%#x\n", __func__, reg_base,
phy_addr, reg_addr, val);
return val;
+}
+static int ls1012a_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr, u16 data)
+{
void *reg_base = bus->priv;
u32 reg;
u32 phy;
u32 reg_data;
int timeout = MDIO_TIMEOUT;
int val;
if (dev_addr == MDIO_DEVAD_NONE) {
reg = ((reg_addr & EMAC_MII_DATA_RA_MASK) <<
EMAC_MII_DATA_RA_SHIFT);
} else {
ls1012a_write_addr(bus, phy_addr, dev_addr, reg_addr);
reg = ((dev_addr & EMAC_MII_DATA_RA_MASK) <<
EMAC_MII_DATA_RA_SHIFT);
}
phy = ((phy_addr & EMAC_MII_DATA_PA_MASK) << EMAC_MII_DATA_PA_SHIFT);
if (dev_addr == MDIO_DEVAD_NONE)
reg_data = (EMAC_MII_DATA_ST | EMAC_MII_DATA_OP_WR |
EMAC_MII_DATA_TA | phy | reg | data);
else
reg_data = (EMAC_MII_DATA_OP_CL45_WR | EMAC_MII_DATA_TA |
phy | reg | data);
writel(reg_data, reg_base + EMAC_MII_DATA_REG);
/*
* wait for the MII interrupt
*/
while (!(readl(reg_base + EMAC_IEVENT_REG) & EMAC_IEVENT_MII)) {
if (timeout-- <= 0) {
printf("Phy MDIO read/write timeout\n");
return -1;
}
}
/*
* clear MII interrupt
*/
writel(EMAC_IEVENT_MII, reg_base + EMAC_IEVENT_REG);
debug("%s: phy: %02x reg:%02x val:%#x\n", __func__, phy_addr,
reg_addr, data);
return val;
+}
+struct mii_dev *ls1012a_mdio_init(struct mdio_info *mdio_info) +{
struct mii_dev *bus;
int ret;
u32 mdio_speed;
u32 pclk = 250000000;
bus = mdio_alloc();
if (!bus) {
printf("mdio_alloc failed\n");
return NULL;
}
bus->read = ls1012a_phy_read;
bus->write = ls1012a_phy_write;
/* MAC1 MDIO used to communicate with external PHYS */
bus->priv = mdio_info->reg_base;
sprintf(bus->name, mdio_info->name);
/* configure mdio speed */
mdio_speed = (DIV_ROUND_UP(pclk, 4000000) << EMAC_MII_SPEED_SHIFT);
mdio_speed |= EMAC_HOLDTIME(0x5);
writel(mdio_speed, mdio_info->reg_base + EMAC_MII_CTRL_REG);
ret = mdio_register(bus);
if (ret) {
printf("mdio_register failed\n");
free(bus);
return NULL;
}
return bus;
+}
+static void ls1012a_configure_serdes(struct ls1012a_eth_dev *priv) +{
struct mii_dev bus;
int value, sgmii_2500 = 0;
struct gemac_s *gem = priv->gem;
if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500)
sgmii_2500 = 1;
printf("%s %d\n", __func__, priv->gemac_port);
/* PCS configuration done with corresponding GEMAC */
bus.priv = gem_info[priv->gemac_port].gemac_base;
ls1012a_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x0);
ls1012a_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x1);
ls1012a_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x2);
ls1012a_phy_read(&bus, 0, MDIO_DEVAD_NONE, 0x3);
/* Reset serdes */
ls1012a_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x0, 0x8000);
/* SGMII IF mode + AN enable only for 1G SGMII, not for 2.5G */
value = PHY_SGMII_IF_MODE_SGMII;
if (!sgmii_2500)
value |= PHY_SGMII_IF_MODE_AN;
else
value |= PHY_SGMII_IF_MODE_SGMII_GBT;
ls1012a_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x14, value);
/* Dev ability according to SGMII specification */
value = PHY_SGMII_DEV_ABILITY_SGMII;
ls1012a_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x4, value);
/* These values taken from validation team */
if (!sgmii_2500) {
ls1012a_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x0);
ls1012a_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0x400);
} else {
ls1012a_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x7);
ls1012a_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0xa120);
}
/* Restart AN */
value = PHY_SGMII_CR_DEF_VAL;
if (!sgmii_2500)
value |= PHY_SGMII_CR_RESET_AN;
ls1012a_phy_write(&bus, 0, MDIO_DEVAD_NONE, 0, value);
+}
+void ls1012a_set_mdio(int dev_id, struct mii_dev *bus) +{
gem_info[dev_id].bus = bus;
+}
+void ls1012a_set_phy_address_mode(int dev_id, int phy_id, int phy_mode) +{
gem_info[dev_id].phy_address = phy_id;
gem_info[dev_id].phy_mode = phy_mode;
+}
+int ls1012a_phy_configure(struct ls1012a_eth_dev *priv, int dev_id, int phy_id) +{
struct phy_device *phydev = NULL;
struct eth_device *dev = priv->dev;
struct gemac_s *gem = priv->gem;
struct ccsr_scfg *scfg = (struct ccsr_scfg *)CONFIG_SYS_FSL_SCFG_ADDR;
/* Configure SGMII PCS */
if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII ||
gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500) {
out_be32(&scfg->mdioselcr, 0x00000000);
ls1012a_configure_serdes(priv);
}
/* By this time on-chip SGMII initialization is done
* we can switch mdio interface to external PHYs
*/
out_be32(&scfg->mdioselcr, 0x80000000);
if (!gem->bus)
return -1;
phydev = phy_connect(gem->bus, phy_id, dev, gem->phy_mode);
if (!phydev) {
printf("phy_connect failed\n");
return -1;
}
phy_config(phydev);
priv->phydev = phydev;
return 0;
+} +#endif
+int gemac_initialize(bd_t *bis, int dev_id, char *devname) +{
struct eth_device *dev;
struct ls1012a_eth_dev *priv;
struct pfe *pfe;
int i;
if (dev_id > 1) {
printf("Invalid port\n");
return -1;
}
dev = (struct eth_device *)malloc(sizeof(struct eth_device));
Please don't add a new driver that uses the legacy API. Make this a driver model driver.
if (!dev)
return -1;
memset(dev, 0, sizeof(struct eth_device));
priv = (struct ls1012a_eth_dev *)malloc(sizeof(struct ls1012a_eth_dev));
if (!priv)
return -1;
gemac_list[dev_id] = priv;
priv->gemac_port = dev_id;
priv->gem = &gem_info[priv->gemac_port];
priv->dev = dev;
pfe = &priv->pfe;
pfe->cbus_baseaddr = (void *)CONFIG_SYS_FSL_PFE_ADDR;
pfe->ddr_baseaddr = (void *)CONFIG_DDR_PFE_BASEADDR;
pfe->ddr_phys_baseaddr = (unsigned long)CONFIG_DDR_PFE_PHYS_BASEADDR;
sprintf(dev->name, devname);
dev->priv = priv;
dev->init = ls1012a_eth_init;
dev->halt = ls1012a_eth_halt;
dev->send = ls1012a_eth_send;
dev->recv = ls1012a_eth_recv;
/* Tell u-boot to get the addr from the env */
for (i = 0; i < 6; i++)
dev->enetaddr[i] = 0;
pfe_probe(pfe);
switch (priv->gemac_port) {
case EMAC_PORT_0:
default:
priv->gem->gemac_base = EMAC1_BASE_ADDR;
priv->gem->egpi_base = EGPI1_BASE_ADDR;
break;
case EMAC_PORT_1:
priv->gem->gemac_base = EMAC2_BASE_ADDR;
priv->gem->egpi_base = EGPI2_BASE_ADDR;
break;
}
+#if defined(CONFIG_PHYLIB)
if (ls1012a_phy_configure(priv, dev_id,
gem_info[priv->gemac_port].phy_address))
return -1;
+#endif
eth_register(dev);
return 0;
+}
[ ... ]