Commit 111fd19e authored by Roy Zang's avatar Roy Zang Committed by Andy Fleming

fm/mEMAC: add mEMAC frame work

The multirate ethernet media access controller (mEMAC) interfaces to
10Gbps and below Ethernet/IEEE 802.3 networks via either RGMII/RMII
interfaces or XAUI/XFI/SGMII/QSGMII using the high-speed SerDes interface.
Signed-off-by: default avatarSandeep Singh <Sandeep@freescale.com>
Signed-off-by: default avatarPoonam Aggrwal <poonam.aggrwal@freescale.com>
Signed-off-by: default avatarRoy Zang <tie-fei.zang@freescale.com>
Signed-off-by: default avatarAndy Fleming <afleming@freescale.com>
parent d2404141
......@@ -499,6 +499,7 @@
#define CONFIG_SYS_NUM_FM2_10GEC 2
#define CONFIG_NUM_DDR_CONTROLLERS 3
#define CONFIG_SYS_FSL_DDR_VER FSL_DDR_VER_4_7
#define CONFIG_SYS_FMAN_V3
#define CONFIG_SYS_FM_MURAM_SIZE 0x60000
#define CONFIG_SYS_FSL_TBCLK_DIV 16
#define CONFIG_SYS_FSL_PCIE_COMPAT "fsl,qoriq-pcie-v3.0"
......@@ -523,6 +524,7 @@
#define CONFIG_SYS_NUM_FM1_10GEC 2
#define CONFIG_NUM_DDR_CONTROLLERS 1
#define CONFIG_SYS_FSL_DDR_VER FSL_DDR_VER_4_7
#define CONFIG_SYS_FMAN_V3
#define CONFIG_SYS_FM_MURAM_SIZE 0x60000
#define CONFIG_SYS_FSL_TBCLK_DIV 16
#define CONFIG_SYS_FSL_PCIE_COMPAT "fsl,qoriq-pcie-v2.4"
......
......@@ -423,6 +423,14 @@ typedef struct fm_10gec_mdio {
u8 res[4*1024];
} fm_10gec_mdio_t;
typedef struct fm_memac {
u8 res[4*1024];
} fm_memac_t;
typedef struct fm_memac_mdio {
u8 res[4*1024];
} fm_memac_mdio_t;
typedef struct fm_1588 {
u8 res[4*1024];
} fm_1588_t;
......@@ -446,6 +454,14 @@ typedef struct ccsr_fman {
u8 res1[8*1024];
fm_soft_parser_t fm_soft_parser;
u8 res2[96*1024];
#ifdef CONFIG_SYS_FMAN_V3
struct {
fm_memac_t fm_memac;
fm_memac_mdio_t fm_memac_mdio;
} memac[10];
u8 res4[32*1024];
fm_memac_mdio_t fm_dedicated_mdio[2];
#else
struct {
fm_dtsec_t fm_dtesc;
fm_mdio_t fm_mdio;
......@@ -455,6 +471,7 @@ typedef struct ccsr_fman {
fm_10gec_mdio_t fm_10gec_mdio;
} mac_10g[1];
u8 res4[48*1024];
#endif
fm_1588_t fm_1588;
u8 res5[4*1024];
} ccsr_fman_t;
......
This diff is collapsed.
......@@ -32,6 +32,10 @@ COBJS-y += init.o
COBJS-y += tgec.o
COBJS-y += tgec_phy.o
# Soc have FMAN v3 with mEMAC
COBJS-$(CONFIG_SYS_FMAN_V3) += memac_phy.o
COBJS-$(CONFIG_SYS_FMAN_V3) += memac.o
# SoC specific SERDES support
COBJS-$(CONFIG_P1017) += p1023.o
COBJS-$(CONFIG_P1023) += p1023.o
......
/*
* Copyright 2009-2011 Freescale Semiconductor, Inc.
* Copyright 2009-2012 Freescale Semiconductor, Inc.
* Dave Liu <daveliu@freescale.com>
*
* This program is free software; you can redistribute it and/or
......@@ -28,6 +28,7 @@
#include <phy.h>
#include <asm/fsl_dtsec.h>
#include <asm/fsl_tgec.h>
#include <asm/fsl_memac.h>
#include "fm.h"
......@@ -47,6 +48,28 @@ static int num_controllers;
/* Configure the TBI for SGMII operation */
void dtsec_configure_serdes(struct fm_eth *priv)
{
#ifdef CONFIG_SYS_FMAN_V3
u32 value;
struct mii_dev bus;
bus.priv = priv->mac->phyregs;
/* SGMII IF mode + AN enable */
value = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII;
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x14, value);
/* Dev ability according to SGMII specification */
value = PHY_SGMII_DEV_ABILITY_SGMII;
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x4, value);
/* Adjust link timer for SGMII -
1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40 */
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x13, 0x3);
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0xd40);
/* Restart AN */
value = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0, value);
#else
struct dtsec *regs = priv->mac->base;
struct tsec_mii_mng *phyregs = priv->mac->phyregs;
......@@ -60,15 +83,18 @@ void dtsec_configure_serdes(struct fm_eth *priv)
TBIANA_SGMII_ACK);
tsec_local_mdio_write(phyregs, in_be32(&regs->tbipa), 0,
TBI_CR, TBICR_SETTINGS);
#endif
}
static void dtsec_init_phy(struct eth_device *dev)
{
struct fm_eth *fm_eth = dev->priv;
struct dtsec *regs = (struct dtsec *)fm_eth->mac->base;
#ifndef CONFIG_SYS_FMAN_V3
struct dtsec *regs = (struct dtsec *)fm_eth->mac->base;
/* Assign a Physical address to the TBI */
out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
#endif
if (fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII)
dtsec_configure_serdes(fm_eth);
......@@ -541,6 +567,10 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
num = fm_eth->num;
#ifdef CONFIG_SYS_FMAN_V3
base = &reg->memac[num].fm_memac;
phyregs = &reg->memac[num].fm_memac_mdio;
#else
/* Get the mac registers base address */
if (fm_eth->type == FM_ETH_1G_E) {
base = &reg->mac_1g[num].fm_dtesc;
......@@ -549,6 +579,7 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
base = &reg->mac_10g[num].fm_10gec;
phyregs = &reg->mac_10g[num].fm_10gec_mdio;
}
#endif
/* alloc mac controller */
mac = malloc(sizeof(struct fsl_enet_mac));
......@@ -559,10 +590,14 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
/* save the mac to fm_eth struct */
fm_eth->mac = mac;
#ifdef CONFIG_SYS_FMAN_V3
init_memac(mac, base, phyregs, MAX_RXBUF_LEN);
#else
if (fm_eth->type == FM_ETH_1G_E)
init_dtsec(mac, base, phyregs, MAX_RXBUF_LEN);
else
init_tgec(mac, base, phyregs, MAX_RXBUF_LEN);
#endif
return 1;
}
......
/*
* Copyright 2012 Freescale Semiconductor, Inc.
* Roy Zang <tie-fei.zang@freescale.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
/* MAXFRM - maximum frame length */
#define MAXFRM_MASK 0x0000ffff
#include <common.h>
#include <phy.h>
#include <asm/types.h>
#include <asm/io.h>
#include <asm/fsl_enet.h>
#include <asm/fsl_memac.h>
#include "fm.h"
static void memac_init_mac(struct fsl_enet_mac *mac)
{
struct memac *regs = mac->base;
/* mask all interrupt */
out_be32(&regs->imask, IMASK_MASK_ALL);
/* clear all events */
out_be32(&regs->ievent, IEVENT_CLEAR_ALL);
/* set the max receive length */
out_be32(&regs->maxfrm, mac->max_rx_len & MAXFRM_MASK);
/* multicast frame reception for the hash entry disable */
out_be32(&regs->hashtable_ctrl, 0);
}
static void memac_enable_mac(struct fsl_enet_mac *mac)
{
struct memac *regs = mac->base;
setbits_be32(&regs->command_config, MEMAC_CMD_CFG_RXTX_EN);
}
static void memac_disable_mac(struct fsl_enet_mac *mac)
{
struct memac *regs = mac->base;
clrbits_be32(&regs->command_config, MEMAC_CMD_CFG_RXTX_EN);
}
static void memac_set_mac_addr(struct fsl_enet_mac *mac, u8 *mac_addr)
{
struct memac *regs = mac->base;
u32 mac_addr0, mac_addr1;
/*
* if a station address of 0x12345678ABCD, perform a write to
* MAC_ADDR0 of 0x78563412, MAC_ADDR1 of 0x0000CDAB
*/
mac_addr0 = (mac_addr[3] << 24) | (mac_addr[2] << 16) | \
(mac_addr[1] << 8) | (mac_addr[0]);
out_be32(&regs->mac_addr_0, mac_addr0);
mac_addr1 = ((mac_addr[5] << 8) | mac_addr[4]) & 0x0000ffff;
out_be32(&regs->mac_addr_1, mac_addr1);
}
static void memac_set_interface_mode(struct fsl_enet_mac *mac,
phy_interface_t type, int speed)
{
/* Roy need more work here */
struct memac *regs = mac->base;
u32 if_mode, if_status;
/* clear all bits relative with interface mode */
if_mode = in_be32(&regs->if_mode);
if_status = in_be32(&regs->if_status);
/* set interface mode */
switch (type) {
case PHY_INTERFACE_MODE_GMII:
if_mode &= ~IF_MODE_MASK;
if_mode |= IF_MODE_GMII;
break;
case PHY_INTERFACE_MODE_RGMII:
if_mode |= (IF_MODE_GMII | IF_MODE_RG);
break;
case PHY_INTERFACE_MODE_RMII:
if_mode |= (IF_MODE_GMII | IF_MODE_RM);
break;
case PHY_INTERFACE_MODE_SGMII:
if_mode &= ~IF_MODE_MASK;
if_mode |= (IF_MODE_GMII);
break;
default:
break;
}
/* Enable automatic speed selection */
if_mode |= IF_MODE_EN_AUTO;
debug(" %s, if_mode = %x\n", __func__, if_mode);
debug(" %s, if_status = %x\n", __func__, if_status);
out_be32(&regs->if_mode, if_mode);
return;
}
void init_memac(struct fsl_enet_mac *mac, void *base,
void *phyregs, int max_rx_len)
{
mac->base = base;
mac->phyregs = phyregs;
mac->max_rx_len = max_rx_len;
mac->init_mac = memac_init_mac;
mac->enable_mac = memac_enable_mac;
mac->disable_mac = memac_disable_mac;
mac->set_mac_addr = memac_set_mac_addr;
mac->set_if_mode = memac_set_interface_mode;
}
/*
* Copyright 2012 Freescale Semiconductor, Inc.
* Andy Fleming <afleming@freescale.com>
* Roy Zang <tie-fei.zang@freescale.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
* Some part is taken from tsec.c
*/
#include <common.h>
#include <miiphy.h>
#include <phy.h>
#include <asm/io.h>
#include <asm/fsl_memac.h>
#include <fm_eth.h>
/*
* Write value to the PHY for this device to the register at regnum, waiting
* until the write is done before it returns. All PHY configuration has to be
* done through the TSEC1 MIIM regs
*/
int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
int regnum, u16 value)
{
u32 mdio_ctl;
struct memac_mdio_controller *regs = bus->priv;
u32 c45 = 1; /* Default to 10G interface */
if (dev_addr == MDIO_DEVAD_NONE) {
c45 = 0; /* clause 22 */
dev_addr = regnum & 0x1f;
clrbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
} else {
setbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
setbits_be32(&regs->mdio_stat, MDIO_STAT_HOLD_15_CLK);
}
/* Wait till the bus is free */
while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
;
/* Set the port and dev addr */
mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
out_be32(&regs->mdio_ctl, mdio_ctl);
/* Set the register address */
if (c45)
out_be32(&regs->mdio_addr, regnum & 0xffff);
/* Wait till the bus is free */
while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
;
/* Write the value to the register */
out_be32(&regs->mdio_data, MDIO_DATA(value));
/* Wait till the MDIO write is complete */
while ((in_be32(&regs->mdio_data)) & MDIO_DATA_BSY)
;
return 0;
}
/*
* Reads from register regnum in the PHY for device dev, returning the value.
* Clears miimcom first. All PHY configuration has to be done through the
* TSEC1 MIIM regs
*/
int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
int regnum)
{
u32 mdio_ctl;
struct memac_mdio_controller *regs = bus->priv;
u32 c45 = 1;
if (dev_addr == MDIO_DEVAD_NONE) {
c45 = 0; /* clause 22 */
dev_addr = regnum & 0x1f;
clrbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
} else {
setbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
setbits_be32(&regs->mdio_stat, MDIO_STAT_HOLD_15_CLK);
}
/* Wait till the bus is free */
while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
;
/* Set the Port and Device Addrs */
mdio_ctl = MDIO_CTL_PORT_ADDR(port_addr) | MDIO_CTL_DEV_ADDR(dev_addr);
out_be32(&regs->mdio_ctl, mdio_ctl);
/* Set the register address */
if (c45)
out_be32(&regs->mdio_addr, regnum & 0xffff);
/* Wait till the bus is free */
while ((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY)
;
/* Initiate the read */
mdio_ctl |= MDIO_CTL_READ;
out_be32(&regs->mdio_ctl, mdio_ctl);
/* Wait till the MDIO write is complete */
while ((in_be32(&regs->mdio_data)) & MDIO_DATA_BSY)
;
/* Return all Fs if nothing was there */
if (in_be32(&regs->mdio_stat) & MDIO_STAT_RD_ER)
return 0xffff;
return in_be32(&regs->mdio_data) & 0xffff;
}
int memac_mdio_reset(struct mii_dev *bus)
{
return 0;
}
int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info)
{
struct mii_dev *bus = mdio_alloc();
if (!bus) {
printf("Failed to allocate FM TGEC MDIO bus\n");
return -1;
}
bus->read = memac_mdio_read;
bus->write = memac_mdio_write;
bus->reset = memac_mdio_reset;
sprintf(bus->name, info->name);
bus->priv = info->regs;
return mdio_register(bus);
}
/*
* Copyright 2009-2011 Freescale Semiconductor, Inc.
* Copyright 2009-2012 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
......@@ -53,8 +53,15 @@ enum fm_eth_type {
FM_ETH_10G_E,
};
#ifdef CONFIG_SYS_FMAN_V3
#define CONFIG_SYS_FM1_DTSEC_MDIO_ADDR (CONFIG_SYS_FSL_FM1_ADDR + 0xfc000)
#define CONFIG_SYS_FM1_TGEC_MDIO_ADDR (CONFIG_SYS_FSL_FM1_ADDR + 0xfd000)
#define CONFIG_SYS_FM2_DTSEC_MDIO_ADDR (CONFIG_SYS_FSL_FM2_ADDR + 0xfc000)
#define CONFIG_SYS_FM2_TGEC_MDIO_ADDR (CONFIG_SYS_FSL_FM2_ADDR + 0xfd000)
#else
#define CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR (CONFIG_SYS_FSL_FM1_ADDR + 0xe1120)
#define CONFIG_SYS_FM1_TGEC_MDIO_ADDR (CONFIG_SYS_FSL_FM1_ADDR + 0xf1000)
#endif
#define DEFAULT_FM_MDIO_NAME "FSL_MDIO0"
#define DEFAULT_FM_TGEC_MDIO_NAME "FM_TGEC_MDIO"
......@@ -65,6 +72,33 @@ enum fm_eth_type {
.phy_regs = (void *)pregs, \
.enet_if = PHY_INTERFACE_MODE_NONE, \
#ifdef CONFIG_SYS_FMAN_V3
#define FM_DTSEC_INFO_INITIALIZER(idx, n) \
{ \
FM_ETH_INFO_INITIALIZER(idx, CONFIG_SYS_FM1_DTSEC_MDIO_ADDR) \
.index = idx, \
.num = n - 1, \
.type = FM_ETH_1G_E, \
.port = FM##idx##_DTSEC##n, \
.rx_port_id = RX_PORT_1G_BASE + n - 1, \
.tx_port_id = TX_PORT_1G_BASE + n - 1, \
.compat_offset = CONFIG_SYS_FSL_FM##idx##_OFFSET + \
offsetof(struct ccsr_fman, memac[n-1]),\
}
#define FM_TGEC_INFO_INITIALIZER(idx, n) \
{ \
FM_ETH_INFO_INITIALIZER(idx, CONFIG_SYS_FM1_TGEC_MDIO_ADDR) \
.index = idx, \
.num = n - 1, \
.type = FM_ETH_10G_E, \
.port = FM##idx##_10GEC##n, \
.rx_port_id = RX_PORT_10G_BASE + n - 1, \
.tx_port_id = TX_PORT_10G_BASE + n - 1, \
.compat_offset = CONFIG_SYS_FSL_FM##idx##_OFFSET + \
offsetof(struct ccsr_fman, memac[n-1]),\
}
#else
#define FM_DTSEC_INFO_INITIALIZER(idx, n) \
{ \
FM_ETH_INFO_INITIALIZER(idx, CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR) \
......@@ -90,7 +124,7 @@ enum fm_eth_type {
.compat_offset = CONFIG_SYS_FSL_FM##idx##_OFFSET + \
offsetof(struct ccsr_fman, mac_10g[n-1]),\
}
#endif
struct fm_eth_info {
u8 enabled;
u8 fm;
......@@ -112,7 +146,14 @@ struct tgec_mdio_info {
char *name;
};
struct memac_mdio_info {
struct memac_mdio_controller *regs;
char *name;
};
int fm_tgec_mdio_init(bd_t *bis, struct tgec_mdio_info *info);
int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info);
int fm_standard_init(bd_t *bis);
void fman_enet_init(void);
void fdt_fixup_fman_ethernet(void *fdt);
......
/*
* Copyright 2009-2010 Freescale Semiconductor, Inc.
* Copyright 2009-2012 Freescale Semiconductor, Inc.
* Jun-jie Zhang <b18070@freescale.com>
* Mingkai Hu <Mingkai.hu@freescale.com>
*
......@@ -51,6 +51,10 @@ int tsec_local_mdio_read(struct tsec_mii_mng *phyregs, int port_addr,
int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum);
int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum,
u16 value);
int memac_mdio_write(struct mii_dev *bus, int port_addr, int dev_addr,
int regnum, u16 value);
int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
int regnum);
struct fsl_pq_mdio_info {
struct tsec_mii_mng *regs;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment