GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
obj-y += sys.o
|
||||
obj-$(CONFIG_FTGMAC030_V1) += ftgmac030.o marvell_phy.o realtek_phy.o
|
||||
obj-$(CONFIG_FTGMAC030_V2) += ftgmac030_v2.o jlsemi_phy.o icplus_phy.o ephy_phy.o
|
||||
@@ -0,0 +1,62 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#ifndef __BSPETH_H__
|
||||
#define __BSPETH_H__
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <malloc.h> /* malloc, free, realloc */
|
||||
|
||||
#include <net.h>
|
||||
#include <miiphy.h>
|
||||
#include <asm/arch/platform.h>
|
||||
|
||||
#ifndef bit
|
||||
#define bit(nr) (1UL << (nr))
|
||||
#endif
|
||||
#define mdelay(n) udelay((n)*1000)
|
||||
|
||||
/* ***********************************************************
|
||||
*
|
||||
* Global varibles
|
||||
*
|
||||
* ***********************************************************
|
||||
*/
|
||||
#define BSPETH_PHY_CRG_REG (CRG_REG_BASE + 0x16c)
|
||||
#define BSPETH_MAC_CRG_REG (CRG_REG_BASE + 0x170)
|
||||
#define BSPETH_CFG_CRG_REG (SYS_CTRL_REG_BASE + 0x134)
|
||||
#define BSPETH_DLY_CRG_REG (SYS_CTRL_REG_BASE + 0x8940)
|
||||
#define BSPETH_DLY_STAT_REG (CRG_REG_BASE + 0x1a8)
|
||||
|
||||
#define ETH_DLY_SEL bit(0)
|
||||
#define ETH_DLY_STAT bit(0)
|
||||
|
||||
#define ETH_SOFT_RESET bit(1)
|
||||
|
||||
#define ETH_EXTERNAL_PHY_RESET bit(1)
|
||||
|
||||
#define ETH_PHY_INTF (bit(0) | bit(3))
|
||||
#define ETH_PHY_RST_N bit(1)
|
||||
|
||||
/* configuerable values */
|
||||
|
||||
/* ***********************************************************
|
||||
*
|
||||
* Only for internal used!
|
||||
*
|
||||
* ***********************************************************
|
||||
*/
|
||||
|
||||
/* read/write IO */
|
||||
|
||||
#define _readl(c) ({ u32 __v = le32_to_cpu(__raw_readl(c)); __v; })
|
||||
#define _writel(v, c) __raw_writel(cpu_to_le32(v), c)
|
||||
|
||||
#define mk_bits(shift, nbits) ((((shift) & 0x1F) << 16) | ((nbits) & 0x1F))
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,149 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <phy.h>
|
||||
|
||||
#define MIIM_EPHY_SUB_CFG 0x12
|
||||
#define MIIM_EPHY_SUB_WDATA 0x13
|
||||
#define MIIM_EPHY_SUB_RDATA 0x14
|
||||
|
||||
#define EPHY_TRIM_REG_BASE (0x12020000 + 0x8a2c)
|
||||
|
||||
typedef union { /* FEPHY TRIM */
|
||||
uint32_t all;
|
||||
struct {
|
||||
uint32_t efuse_tx_100_fs :4;
|
||||
uint32_t efuse_tx_10_outr :4;
|
||||
uint32_t efuse_tx_10_fs :4;
|
||||
uint32_t efuse_rcal_code_rt :4;
|
||||
uint32_t reserved :16;
|
||||
} bitc;
|
||||
} EPHY_TRIM_REG;
|
||||
|
||||
|
||||
static int ephy_phy_extread(struct phy_device *phydev, int addr,
|
||||
int devaddr, int regnum)
|
||||
{
|
||||
int val;
|
||||
int sub_cfg;
|
||||
|
||||
sub_cfg = (0<<15) | (devaddr << 8) | (regnum << 0);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_EPHY_SUB_CFG, sub_cfg);
|
||||
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_EPHY_SUB_RDATA);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int ephy_phy_extwrite(struct phy_device *phydev, int addr,
|
||||
int devaddr, int regnum, u16 val)
|
||||
{
|
||||
int sub_cfg;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_EPHY_SUB_WDATA, val);
|
||||
|
||||
sub_cfg = (1<<15) | (devaddr << 8) | (regnum << 0);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_EPHY_SUB_CFG, sub_cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int ephy_config(struct phy_device *phydev)
|
||||
{
|
||||
unsigned int reg;
|
||||
EPHY_TRIM_REG ephy_trim_reg;
|
||||
|
||||
/* Set green LED for Link, yellow LED for Active */
|
||||
//set LED to 0 (page 25 reg 0 3:2:0)
|
||||
reg = phydev->drv->readext(phydev, 0, 0x19, 0x00);
|
||||
reg &= ~(0x07);
|
||||
reg |= 0x03;
|
||||
phydev->drv->writeext(phydev, 0, 0x19, 0x00, reg);
|
||||
|
||||
/* Set RG_EPHY_TX_100_LPF fix 4 to Improve the waveform */
|
||||
//set RG_EPHY_TX_100_LPF(page 0 reg 33 7:4)
|
||||
reg = phydev->drv->readext(phydev, 0, 0x0, 0x21);
|
||||
reg &= ~(0xf0);
|
||||
reg |= 0x40;
|
||||
phydev->drv->writeext(phydev, 0, 0x0, 0x21, reg);
|
||||
|
||||
//page 12 reg 4
|
||||
phydev->drv->writeext(phydev, 0, 0x0c, 0x4, 0x10);
|
||||
|
||||
ephy_trim_reg.all = readl(EPHY_TRIM_REG_BASE);
|
||||
|
||||
if (!ephy_trim_reg.all) {
|
||||
ephy_trim_reg.bitc.efuse_tx_10_outr = 0;
|
||||
ephy_trim_reg.bitc.efuse_tx_10_fs = 0;
|
||||
ephy_trim_reg.bitc.efuse_tx_100_fs = 4;
|
||||
ephy_trim_reg.bitc.efuse_rcal_code_rt = 8;
|
||||
}
|
||||
|
||||
pr_info("trim_reg:0x%x\n", ephy_trim_reg.all);
|
||||
pr_info("tx_100_fs:0x%x tx_10_outr:0x%x\n", ephy_trim_reg.bitc.efuse_tx_100_fs, ephy_trim_reg.bitc.efuse_tx_10_outr);
|
||||
pr_info("tx_10_fs:0x%x rcal_code:0x%x\n", ephy_trim_reg.bitc.efuse_tx_10_fs, ephy_trim_reg.bitc.efuse_rcal_code_rt);
|
||||
|
||||
|
||||
if (ephy_trim_reg.all) {
|
||||
//set EPHY_TX_10_OUTR to 0 (page 0 reg 9 11:8)
|
||||
reg = phydev->drv->readext(phydev, 0, 0, 0x09);
|
||||
reg &= ~(0xf << 8);
|
||||
reg |= (ephy_trim_reg.bitc.efuse_tx_10_outr << 8);
|
||||
phydev->drv->writeext(phydev, 0, 0, 0x09, reg);
|
||||
|
||||
//set EPHY_TX_10_FS to 0 (page 0 reg 9 7:4)
|
||||
reg = phydev->drv->readext(phydev, 0, 0, 0x09);
|
||||
reg &= ~(0xf << 4);
|
||||
reg |= (ephy_trim_reg.bitc.efuse_tx_10_fs << 4);
|
||||
phydev->drv->writeext(phydev, 0, 0, 0x09, reg);
|
||||
|
||||
//set EPHY_TX_100_FS to 4 (page 0 reg 33 3:0)
|
||||
reg = phydev->drv->readext(phydev, 0, 0, 0x21);
|
||||
reg &= ~(0xf << 0);
|
||||
reg |= (ephy_trim_reg.bitc.efuse_tx_100_fs << 0);
|
||||
phydev->drv->writeext(phydev, 0, 0, 0x21, reg);
|
||||
|
||||
// set EPHY_RCAL_CODE_FT to 8 (page 0 reg 34 7:4)
|
||||
reg = phydev->drv->readext(phydev, 0, 0, 0x22);
|
||||
reg &= ~(0xf << 4);
|
||||
reg |= (ephy_trim_reg.bitc.efuse_rcal_code_rt << 4);
|
||||
phydev->drv->writeext(phydev, 0, 0, 0x22, reg);
|
||||
}
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ephy_aneg_done(struct phy_device *phydev)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
reg = phydev->drv->readext(phydev, 0, 0x11, 0x20);
|
||||
|
||||
pr_info("[EPHY]:0x%x\n", reg);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Support for ePHY PHY */
|
||||
static struct phy_driver ephy_driver = {
|
||||
.name = "ePHY",
|
||||
.uid = 0x0243991f,
|
||||
.mask = 0xffffffff,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &ephy_config,
|
||||
.startup = &genphy_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
.readext = &ephy_phy_extread,
|
||||
.writeext = &ephy_phy_extwrite,
|
||||
.aneg_done = &ephy_aneg_done,
|
||||
};
|
||||
|
||||
int phy_ephy_init(void)
|
||||
{
|
||||
phy_register(&ephy_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,677 @@
|
||||
/*
|
||||
* Copyright (c) LOTUS. All rights reserved.
|
||||
*/
|
||||
//#define DEBUG
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <wait_bit.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <cpu_func.h>
|
||||
#include <miiphy.h>
|
||||
#include <hexdump.h>
|
||||
|
||||
#include "ftgmac030.h"
|
||||
#include "marvell_phy.h"
|
||||
#include "realtek_phy.h"
|
||||
#include "sys.h"
|
||||
|
||||
#define ETH_ZLEN 60
|
||||
|
||||
/* Receive Buffer Size Register - HW default is 0x640 */
|
||||
#define FTGMAC030_RBSR_DEFAULT_VALUE 0x640
|
||||
|
||||
/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */
|
||||
#define FTGMAC030_PKTBUFSTX 4 /* must be power of 2 */
|
||||
#define FTGMAC030_PKTBUFSRX PKTBUFSRX /* must be power of 2 */
|
||||
|
||||
/* Timeout for transmit */
|
||||
#define FTGMAC030_TX_TIMEOUT_MS 1000
|
||||
|
||||
/* Timeout for a mdio read/write operation */
|
||||
#define FTGMAC030_MDIO_TIMEOUT_USEC 10000
|
||||
|
||||
#define MAC_LEN 6
|
||||
|
||||
struct ftgmac030_data {
|
||||
struct ftgmac030_txdes txdes[FTGMAC030_PKTBUFSTX] __attribute__((aligned(ARCH_DMA_MINALIGN)));
|
||||
struct ftgmac030_rxdes rxdes[FTGMAC030_PKTBUFSRX] __attribute__((aligned(ARCH_DMA_MINALIGN)));
|
||||
int rsvd1 __attribute__((aligned(ARCH_DMA_MINALIGN)));
|
||||
int tx_index;
|
||||
int rx_index;
|
||||
int phy_addr;
|
||||
enum ftgmac030_if_mode phy_intf;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct mdio functions
|
||||
*/
|
||||
int ftgmac030_mdio_read(struct eth_device *dev, int phy_addr,
|
||||
int regnum)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
int phycr;
|
||||
int data;
|
||||
int ret;
|
||||
|
||||
phycr = readl(&ftgmac030->phycr);
|
||||
|
||||
/* preserve MDC cycle threshold */
|
||||
phycr &= FTGMAC030_PHYCR_MDC_CYCTHR_MASK;
|
||||
|
||||
phycr |= FTGMAC030_PHYCR_PHYAD(phy_addr)
|
||||
| FTGMAC030_PHYCR_REGAD(regnum)
|
||||
| FTGMAC030_PHYCR_OP(FTGMAC030_MDIO_OP_RD)
|
||||
| FTGMAC030_PHYCR_SOF(FTGMAC030_MDIO_SOF)
|
||||
| FTGMAC030_PHYCR_PHYRD;
|
||||
|
||||
writel(phycr, &ftgmac030->phycr);
|
||||
|
||||
ret = readl_poll_timeout(&ftgmac030->phycr, phycr,
|
||||
!(phycr & FTGMAC030_PHYCR_PHYRD),
|
||||
FTGMAC030_MDIO_TIMEOUT_USEC);
|
||||
if (ret) {
|
||||
pr_err("mdio read failed (phy:%d reg:%x)\n", phy_addr, regnum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
data = readl(&ftgmac030->phydata);
|
||||
|
||||
return FTGMAC030_PHYDATA_MIIRDATA(data);
|
||||
}
|
||||
|
||||
int ftgmac030_mdio_write(struct eth_device *dev, int phy_addr,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
int phycr;
|
||||
int data;
|
||||
int ret;
|
||||
|
||||
phycr = readl(&ftgmac030->phycr);
|
||||
|
||||
/* preserve MDC cycle threshold */
|
||||
phycr &= FTGMAC030_PHYCR_MDC_CYCTHR_MASK;
|
||||
|
||||
phycr |= FTGMAC030_PHYCR_PHYAD(phy_addr)
|
||||
| FTGMAC030_PHYCR_REGAD(regnum)
|
||||
| FTGMAC030_PHYCR_OP(FTGMAC030_MDIO_OP_WR)
|
||||
| FTGMAC030_PHYCR_SOF(FTGMAC030_MDIO_SOF)
|
||||
| FTGMAC030_PHYCR_PHYWR;
|
||||
|
||||
data = FTGMAC030_PHYDATA_MIIWDATA(value);
|
||||
|
||||
writel(data, &ftgmac030->phydata);
|
||||
writel(phycr, &ftgmac030->phycr);
|
||||
|
||||
ret = readl_poll_timeout(&ftgmac030->phycr, phycr,
|
||||
!(phycr & FTGMAC030_PHYCR_PHYWR),
|
||||
FTGMAC030_MDIO_TIMEOUT_USEC);
|
||||
if (ret) {
|
||||
pr_err("mdio write failed (phy:%d reg:%x)\n", phy_addr, regnum);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* MDIO Bus Interface */
|
||||
static int ftgmac030_mdiobus_read(struct mii_dev *bus, int addr, int devad, int reg)
|
||||
{
|
||||
struct eth_device *dev = (struct eth_device *)bus->priv;
|
||||
|
||||
return ftgmac030_mdio_read(dev, addr, reg);
|
||||
}
|
||||
|
||||
static int ftgmac030_mdiobus_write(struct mii_dev *bus, int addr, int devad,
|
||||
int reg, u16 value)
|
||||
{
|
||||
struct eth_device *dev = (struct eth_device *)bus->priv;
|
||||
|
||||
return ftgmac030_mdio_write(dev, addr, reg, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Init MIDO MDC CYCTHR
|
||||
*/
|
||||
static void ftgmac030_mdc_cycthr(struct eth_device *dev, unsigned int mdc_cycthr)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
int phycr;
|
||||
|
||||
phycr = readl(&ftgmac030->phycr);
|
||||
phycr &= ~FTGMAC030_PHYCR_MDC_CYCTHR_MASK;
|
||||
phycr |= FTGMAC030_PHYCR_MDC_CYCTHR(mdc_cycthr);
|
||||
writel(phycr, &ftgmac030->phycr);
|
||||
}
|
||||
|
||||
static void ftgmac030_set_phy_intf(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
|
||||
priv->phy_intf = (bspeth_get_phy_intf() ? FTGMAC030_MODE_RGMII : FTGMAC030_MODE_RMII);
|
||||
|
||||
printf("%s (%s)\n", __func__, (FTGMAC030_MODE_RMII == priv->phy_intf) ? "rmii" : "rgmii");
|
||||
|
||||
writel(priv->phy_intf, &ftgmac030->gisr);
|
||||
|
||||
/* set the mdc cycthr */
|
||||
/* set the mdc cycthr sys_clk=200M*/
|
||||
ftgmac030_mdc_cycthr(dev, 0xc8);
|
||||
}
|
||||
|
||||
int ftgmac030_mdiobus_init(struct eth_device *dev)
|
||||
{
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
struct mii_dev *bus = mdio_alloc();
|
||||
|
||||
if (!bus) {
|
||||
printf("Failed to allocate MDIO bus\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bus->priv = dev;
|
||||
bus->read = ftgmac030_mdiobus_read;
|
||||
bus->write = ftgmac030_mdiobus_write;
|
||||
snprintf(bus->name, sizeof(bus->name), dev->name);
|
||||
|
||||
if (mdio_register(bus)) {
|
||||
mdio_free(bus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
miiphy_set_current_dev(dev->name);
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftgmac030_phy_reset(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
int i;
|
||||
u16 status, adv;
|
||||
|
||||
adv = ADVERTISE_CSMA | ADVERTISE_ALL;
|
||||
|
||||
ftgmac030_mdio_write(dev, priv->phy_addr, MII_ADVERTISE, adv);
|
||||
|
||||
printf("%s: Starting autonegotiation...\n", dev->name);
|
||||
|
||||
ftgmac030_mdio_write(dev, priv->phy_addr,
|
||||
MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART));
|
||||
|
||||
for (i = 0; i < 10000; i++) {
|
||||
status = ftgmac030_mdio_read(dev, priv->phy_addr, MII_BMSR);
|
||||
if (status & BMSR_ANEGCOMPLETE)
|
||||
break;
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
if (status & BMSR_ANEGCOMPLETE) {
|
||||
printf("%s: Autonegotiation complete\n", dev->name);
|
||||
} else {
|
||||
printf("%s: Autonegotiation timed out (status=0x%04x)\n",
|
||||
dev->name, status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ftgmac030_phy_init(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
|
||||
int phy_addr;
|
||||
u16 phy_id, status, adv, lpa;
|
||||
u16 stat_ge;
|
||||
int media, speed, duplex;
|
||||
int i;
|
||||
|
||||
/* Check if the PHY is up to snuff... */
|
||||
for (phy_addr = 0; phy_addr < 32; phy_addr++) {
|
||||
phy_id = ftgmac030_mdio_read(dev, phy_addr, MII_PHYSID1);
|
||||
/*
|
||||
* When it is unable to found PHY,
|
||||
* the interface usually return 0xffff or 0x0000
|
||||
*/
|
||||
if (phy_id != 0xffff && phy_id != 0x0) {
|
||||
printf("%s: found PHY(0x%x) at 0x%02x\n",
|
||||
dev->name, phy_id, phy_addr);
|
||||
priv->phy_addr = phy_addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (phy_id == 0xffff || phy_id == 0x0) {
|
||||
printf("%s: no PHY present\n", dev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (phy_id == PHY_MARVELL)
|
||||
marvell_phy_init(dev, phy_addr);
|
||||
|
||||
if (phy_id == PHY_REALTEK)
|
||||
realtek_phy_init(dev, phy_addr);
|
||||
|
||||
status = ftgmac030_mdio_read(dev, priv->phy_addr, MII_BMSR);
|
||||
if (!(status & BMSR_LSTATUS)) {
|
||||
/* Try to re-negotiate if we don't have link already. */
|
||||
ftgmac030_phy_reset(dev);
|
||||
|
||||
for (i = 0; i < 100000 / 100; i++) {
|
||||
status = ftgmac030_mdio_read(dev, priv->phy_addr, MII_BMSR);
|
||||
if (status & BMSR_LSTATUS)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(status & BMSR_LSTATUS)) {
|
||||
printf("%s: link down\n", dev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (FTGMAC030_MODE_RGMII == priv->phy_intf) {
|
||||
/* 1000 Base-T Status Register */
|
||||
stat_ge = ftgmac030_mdio_read(dev, priv->phy_addr, MII_STAT1000);
|
||||
speed = (stat_ge & (LPA_1000FULL | LPA_1000HALF)
|
||||
? 1 : 0);
|
||||
|
||||
duplex = ((stat_ge & LPA_1000FULL)
|
||||
? 1 : 0);
|
||||
|
||||
if (speed) { /* Speed is 1000 */
|
||||
printf("%s: link up, 1000bps %s-duplex\n",
|
||||
dev->name, duplex ? "full" : "half");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
adv = ftgmac030_mdio_read(dev, priv->phy_addr, MII_ADVERTISE);
|
||||
lpa = ftgmac030_mdio_read(dev, priv->phy_addr, MII_LPA);
|
||||
|
||||
media = mii_nway_result(lpa & adv);
|
||||
speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 1 : 0);
|
||||
duplex = (media & ADVERTISE_FULL) ? 1 : 0;
|
||||
|
||||
printf("%s: link up, %sMbps %s-duplex\n",
|
||||
dev->name, speed ? "100" : "10", duplex ? "full" : "half");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ftgmac030_update_link_speed(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
|
||||
unsigned short stat_fe;
|
||||
unsigned short stat_ge = 0 ;
|
||||
unsigned int maccr;
|
||||
|
||||
if (FTGMAC030_MODE_RGMII == priv->phy_intf) {
|
||||
/* 1000 Base-T Status Register */
|
||||
stat_ge = ftgmac030_mdio_read(dev, priv->phy_addr, MII_STAT1000);
|
||||
}
|
||||
|
||||
stat_fe = ftgmac030_mdio_read(dev, priv->phy_addr, MII_BMSR);
|
||||
|
||||
if (!(stat_fe & BMSR_LSTATUS)) /* link status up? */
|
||||
return 0;
|
||||
|
||||
/* read MAC control register and clear related bits */
|
||||
maccr = readl(&ftgmac030->maccr) &
|
||||
~(FTGMAC030_MACCR_SPEED_1000 |
|
||||
FTGMAC030_MACCR_SPEED_100 |
|
||||
FTGMAC030_MACCR_FULLDUP);
|
||||
|
||||
if (FTGMAC030_MODE_RGMII == priv->phy_intf) {
|
||||
if (stat_ge & LPA_1000FULL) {
|
||||
/* set gmac for 1000BaseTX and Full Duplex */
|
||||
maccr |= FTGMAC030_MACCR_SPEED_1000 | FTGMAC030_MACCR_FULLDUP;
|
||||
}
|
||||
|
||||
if (stat_ge & LPA_1000HALF) {
|
||||
/* set gmac for 1000BaseTX and Half Duplex */
|
||||
maccr |= FTGMAC030_MACCR_SPEED_1000;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(maccr & FTGMAC030_MACCR_SPEED_1000)) {
|
||||
if (stat_fe & BMSR_100FULL) {
|
||||
/* set MII for 100BaseTX and Full Duplex */
|
||||
maccr |= FTGMAC030_MACCR_SPEED_100 | FTGMAC030_MACCR_FULLDUP;
|
||||
}
|
||||
|
||||
if (stat_fe & BMSR_10FULL) {
|
||||
/* set MII for 10BaseT and Full Duplex */
|
||||
maccr |= FTGMAC030_MACCR_FULLDUP;
|
||||
}
|
||||
|
||||
if (stat_fe & BMSR_100HALF) {
|
||||
/* set MII for 100BaseTX and Half Duplex */
|
||||
maccr |= FTGMAC030_MACCR_SPEED_100;
|
||||
}
|
||||
|
||||
if (stat_fe & BMSR_10HALF) {
|
||||
/* set MII for 10BaseT and Half Duplex */
|
||||
/* we have already clear these bits, do nothing */
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
/* update MII config into maccr */
|
||||
writel(maccr, &ftgmac030->maccr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset MAC
|
||||
*/
|
||||
static void ftgmac030_reset(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
|
||||
debug("%s()\n", __func__);
|
||||
|
||||
writel(FTGMAC030_MACCR_SW_RST, &ftgmac030->maccr);
|
||||
|
||||
while (readl(&ftgmac030->maccr) & FTGMAC030_MACCR_SW_RST)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set MAC address
|
||||
*/
|
||||
static void ftgmac030_set_mac(struct eth_device *dev,
|
||||
const unsigned char *mac)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
unsigned int maddr = mac[0] << 8 | mac[1];
|
||||
unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
|
||||
|
||||
debug("%s(%x %x)\n", __func__, maddr, laddr);
|
||||
|
||||
writel(maddr, &ftgmac030->mac_madr);
|
||||
writel(laddr, &ftgmac030->mac_ladr);
|
||||
}
|
||||
|
||||
static void ftgmac030_set_mac_from_env(struct eth_device *dev)
|
||||
{
|
||||
unsigned char mac[MAC_LEN];
|
||||
|
||||
memset(mac, 0, sizeof(mac));
|
||||
|
||||
if (!eth_env_get_enetaddr("ethaddr", mac)) {
|
||||
printf("MAC address invalid!\n");
|
||||
#ifdef CONFIG_NET_RANDOM_ETHADDR
|
||||
net_random_ethaddr(mac);
|
||||
printf("Set Random MAC address!\n");
|
||||
eth_env_set_enetaddr("ethaddr", mac);
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy(dev->enetaddr, mac, MAC_LEN);
|
||||
|
||||
ftgmac030_set_mac(dev, dev->enetaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* disable transmitter, receiver
|
||||
*/
|
||||
static void ftgmac030_halt(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
|
||||
debug("%s()\n", __func__);
|
||||
|
||||
writel(0, &ftgmac030->maccr);
|
||||
|
||||
bspeth_sys_exit();
|
||||
}
|
||||
|
||||
static int ftgmac030_init(struct eth_device *dev, bd_t *bd)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
unsigned int maccr;
|
||||
ulong start, end;
|
||||
int i;
|
||||
|
||||
debug("%s()\n", __func__);
|
||||
|
||||
/* sys-func-sel */
|
||||
bspeth_sys_init();
|
||||
|
||||
ftgmac030_reset(dev);
|
||||
|
||||
/* set the MII interface */
|
||||
ftgmac030_set_phy_intf(dev);
|
||||
|
||||
/* set the ethernet address */
|
||||
ftgmac030_set_mac_from_env(dev);
|
||||
|
||||
/* disable all interrupts */
|
||||
writel(0, &ftgmac030->ier);
|
||||
|
||||
/* initialize descriptors */
|
||||
priv->tx_index = 0;
|
||||
priv->rx_index = 0;
|
||||
|
||||
for (i = 0; i < FTGMAC030_PKTBUFSTX; i++) {
|
||||
/* TXBUF_BADR */
|
||||
priv->txdes[i].txdes3 = 0;
|
||||
priv->txdes[i].txdes0 = 0;
|
||||
}
|
||||
priv->txdes[FTGMAC030_PKTBUFSTX - 1].txdes0 = FTGMAC030_TXDES0_EDOTR;
|
||||
|
||||
start = ((ulong)&priv->txdes[0]) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
end = start + roundup(sizeof(priv->txdes), ARCH_DMA_MINALIGN);
|
||||
flush_dcache_range(start, end);
|
||||
|
||||
for (i = 0; i < FTGMAC030_PKTBUFSRX; i++) {
|
||||
/* RXBUF_BADR */
|
||||
priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i];
|
||||
priv->rxdes[i].rxdes0 = 0;
|
||||
}
|
||||
priv->rxdes[FTGMAC030_PKTBUFSRX - 1].rxdes0 = FTGMAC030_RXDES0_EDORR;
|
||||
|
||||
start = ((ulong)&priv->rxdes[0]) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
end = start + roundup(sizeof(priv->rxdes), ARCH_DMA_MINALIGN);
|
||||
flush_dcache_range(start, end);
|
||||
|
||||
/* transmit ring */
|
||||
writel((unsigned int)priv->txdes, &ftgmac030->nptxdesc_addr);
|
||||
|
||||
/* receive ring */
|
||||
writel((unsigned int)priv->rxdes, &ftgmac030->rxdesc_addr);
|
||||
|
||||
/* poll receive descriptor automatically */
|
||||
writel(FTGMAC030_APTC_DEFAULT, &ftgmac030->aptc);
|
||||
|
||||
/* config receive buffer size register */
|
||||
writel(FTGMAC030_RBSR_RXBUF_SIZE(FTGMAC030_RBSR_DEFAULT_VALUE), &ftgmac030->rbsr);
|
||||
|
||||
/* enable transmitter, receiver */
|
||||
maccr = FTGMAC030_MACCR_DEFAULT;
|
||||
writel(maccr, &ftgmac030->maccr);
|
||||
|
||||
if (ftgmac030_phy_init(dev)) {
|
||||
if (!ftgmac030_update_link_speed(dev))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a data block via Ethernet
|
||||
*/
|
||||
static int ftgmac030_recv(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
struct ftgmac030_rxdes *curr_des = &priv->rxdes[priv->rx_index];
|
||||
unsigned short rxlen;
|
||||
ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
ulong des_end = des_start +
|
||||
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
|
||||
ulong data_start = curr_des->rxdes3;
|
||||
ulong data_end;
|
||||
|
||||
invalidate_dcache_range(des_start, des_end);
|
||||
|
||||
if (!(curr_des->rxdes0 & FTGMAC030_RXDES0_RXPKT_RDY))
|
||||
return -EAGAIN;
|
||||
|
||||
if (curr_des->rxdes0 & (FTGMAC030_RXDES0_RX_ERR |
|
||||
FTGMAC030_RXDES0_CRC_ERR |
|
||||
FTGMAC030_RXDES0_FTL |
|
||||
FTGMAC030_RXDES0_RUNT |
|
||||
FTGMAC030_RXDES0_RX_ODD_NB)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
rxlen = FTGMAC030_RXDES0_VDBC(curr_des->rxdes0);
|
||||
|
||||
debug("%s(): RX buffer %d, %x received\n",
|
||||
__func__, priv->rx_index, rxlen);
|
||||
|
||||
/* Invalidate received data */
|
||||
data_end = data_start + roundup(rxlen, ARCH_DMA_MINALIGN);
|
||||
invalidate_dcache_range(data_start, data_end);
|
||||
|
||||
/* pass the packet up to the protocol layers. */
|
||||
net_process_received_packet((void *)curr_des->rxdes3, rxlen);
|
||||
|
||||
/* Release buffer to DMA and flush descriptor */
|
||||
curr_des->rxdes0 &= FTGMAC030_RXDES0_EDORR;
|
||||
curr_des->rxdes1 = 0x0;
|
||||
flush_dcache_range(des_start, des_end);
|
||||
|
||||
/* Move to next descriptor */
|
||||
priv->rx_index = (priv->rx_index + 1) % FTGMAC030_PKTBUFSRX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 ftgmac030_read_txdesc(const void *desc)
|
||||
{
|
||||
const struct ftgmac030_txdes *txdes = desc;
|
||||
ulong des_start = ((ulong)txdes) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
ulong des_end = des_start + roundup(sizeof(*txdes), ARCH_DMA_MINALIGN);
|
||||
|
||||
invalidate_dcache_range(des_start, des_end);
|
||||
|
||||
return txdes->txdes0;
|
||||
}
|
||||
|
||||
BUILD_WAIT_FOR_BIT(ftgmac030_txdone, u32, ftgmac030_read_txdesc)
|
||||
|
||||
/*
|
||||
* Send a data block via Ethernet
|
||||
*/
|
||||
static int ftgmac030_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_txdes *curr_des = &priv->txdes[priv->tx_index];
|
||||
ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
ulong des_end = des_start +
|
||||
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
|
||||
ulong data_start;
|
||||
ulong data_end;
|
||||
int rc;
|
||||
|
||||
invalidate_dcache_range(des_start, des_end);
|
||||
|
||||
if (curr_des->txdes0 & FTGMAC030_TXDES0_TXDMA_OWN) {
|
||||
debug("%s(): no TX descriptor available\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("%s(%x, %x)\n", __func__, (int)packet, length);
|
||||
|
||||
length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
|
||||
|
||||
/* initiate a transmit sequence */
|
||||
curr_des->txdes3 = (unsigned int)packet; /* TXBUF_BADR */
|
||||
|
||||
/* Flush data to be sent */
|
||||
data_start = curr_des->txdes3;
|
||||
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
|
||||
flush_dcache_range(data_start, data_end);
|
||||
|
||||
/* only one descriptor on TXBUF */
|
||||
curr_des->txdes0 &= FTGMAC030_TXDES0_EDOTR;
|
||||
curr_des->txdes0 |= FTGMAC030_TXDES0_FTS |
|
||||
FTGMAC030_TXDES0_LTS |
|
||||
FTGMAC030_TXDES0_BUF_SIZE(length) |
|
||||
FTGMAC030_TXDES0_TXDMA_OWN ;
|
||||
|
||||
/* Flush modified buffer descriptor */
|
||||
flush_dcache_range(des_start, des_end);
|
||||
|
||||
/* start transmit */
|
||||
writel(1, &ftgmac030->nptxpd);
|
||||
|
||||
/* wait for transfer to succeed */
|
||||
rc = wait_for_bit_ftgmac030_txdone(curr_des,
|
||||
FTGMAC030_TXDES0_TXDMA_OWN, false,
|
||||
FTGMAC030_TX_TIMEOUT_MS, true);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
debug("%s(): packet sent\n", __func__);
|
||||
|
||||
/* Move to next descriptor */
|
||||
priv->tx_index = (priv->tx_index + 1) % FTGMAC030_PKTBUFSTX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftgmac030_initialize(bd_t *bd)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
struct ftgmac030_data *priv;
|
||||
|
||||
dev = malloc(sizeof *dev);
|
||||
if (!dev) {
|
||||
printf("%s(): failed to allocate dev\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Transmit and receive descriptors should align to 16 bytes */
|
||||
priv = memalign(ARCH_DMA_MINALIGN, sizeof(struct ftgmac030_data));
|
||||
if (!priv) {
|
||||
printf("%s(): failed to allocate priv\n", __func__);
|
||||
goto free_dev;
|
||||
}
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
|
||||
sprintf(dev->name, "FTGMAC030");
|
||||
dev->iobase = GMAC_REG_BASE;
|
||||
dev->init = ftgmac030_init;
|
||||
dev->halt = ftgmac030_halt;
|
||||
dev->send = ftgmac030_send;
|
||||
dev->recv = ftgmac030_recv;
|
||||
dev->priv = priv;
|
||||
|
||||
ftgmac030_mdiobus_init(dev);
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
return 1;
|
||||
|
||||
free_dev:
|
||||
free(dev);
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright (c) LOTUS. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __FTGMAC030_H
|
||||
#define __FTGMAC030_H
|
||||
|
||||
/* The registers offset table of ftgmac030 */
|
||||
struct ftgmac030 {
|
||||
volatile unsigned int isr; /* 0x00 */
|
||||
volatile unsigned int ier; /* 0x04 */
|
||||
volatile unsigned int mac_madr; /* 0x08 */
|
||||
volatile unsigned int mac_ladr; /* 0x0C */
|
||||
volatile unsigned int maht0; /* 0x10 */
|
||||
volatile unsigned int maht1; /* 0x14 */
|
||||
volatile unsigned int nptxpd; /* 0x18 */
|
||||
volatile unsigned int rxpd; /*0x1C */
|
||||
volatile unsigned int nptxdesc_addr; /* 0x20 */
|
||||
volatile unsigned int rxdesc_addr; /* 0x24 */
|
||||
volatile unsigned int hptxpd; /* 0x28 */
|
||||
volatile unsigned int hptxdesc_addr; /*0x2C */
|
||||
volatile unsigned int txitc; /* 0x30 */
|
||||
volatile unsigned int rxitc; /* 0x34 */
|
||||
volatile unsigned int aptc; /* 0x38 */
|
||||
volatile unsigned int dblac; /* 0x3C */
|
||||
volatile unsigned int dmafifos; /* 0x40 */
|
||||
volatile unsigned int rsvd1; /* 0x44 */
|
||||
volatile unsigned int tfafcr; /* 0x48 */
|
||||
volatile unsigned int rbsr; /* 0x4C */
|
||||
volatile unsigned int maccr; /* 0x50 */
|
||||
volatile unsigned int macsr; /* 0x54 */
|
||||
volatile unsigned int tm; /* 0x58 */
|
||||
volatile unsigned int rsvd2; /* 0x5C */
|
||||
volatile unsigned int phycr; /* 0x60 */
|
||||
volatile unsigned int phydata;/* 0x64 */
|
||||
volatile unsigned int flow_cntrl; /* 0x68 */
|
||||
volatile unsigned int back_pressure; /* 0x6C */
|
||||
volatile unsigned int wakeOnLan_cntrl; /* 0x70 */
|
||||
volatile unsigned int wakeOnLan_sts; /* 0x74 */
|
||||
volatile unsigned int wfc_crc; /* 0x78 */
|
||||
volatile unsigned int rsvd3; /* 0x7C */
|
||||
volatile unsigned int wfbm1; /* 0x80 */
|
||||
volatile unsigned int wfbm2; /* 0x84 */
|
||||
volatile unsigned int wfbm3; /* 0x88 */
|
||||
volatile unsigned int wfbm4; /* 0x8C */
|
||||
volatile unsigned int nptxr_ptr; /* 0x90 */
|
||||
volatile unsigned int hptxr_prt; /* 0x94 */
|
||||
volatile unsigned int rxr_ptr; /* 0x98 */
|
||||
volatile unsigned int rsvd4; /* 0x9C */
|
||||
volatile unsigned int tpkt_cnt; /* 0xA0 */
|
||||
volatile unsigned int tx_m_s_col; /* 0xA4 */
|
||||
volatile unsigned int tx_e_f_cnt; /* 0xA8 */
|
||||
volatile unsigned int tx_l_u_cnt; /* 0xAC */
|
||||
volatile unsigned int rpkt_cnt; /* 0xB0 */
|
||||
volatile unsigned int bropkt_cnt; /* 0xB4 */
|
||||
volatile unsigned int mulpkt_cnt; /* 0xB8 */
|
||||
volatile unsigned int rpf_aep_cnt; /* 0xBC */
|
||||
volatile unsigned int runt; /* 0xC0 */
|
||||
volatile unsigned int crcer_ftl_cnt; /* 0xC4 */
|
||||
volatile unsigned int rcol_rlost_cnt; /* 0xC8 */
|
||||
volatile unsigned int bistr; /* 0xCC */
|
||||
volatile unsigned int bmrcr; /* 0xD0 */
|
||||
volatile unsigned int rsvd5[4]; /* 0xD4 ~ 0xE3 */
|
||||
volatile unsigned int acir; /* 0xE4 AXI additional Control Information */
|
||||
volatile unsigned int gisr; /* 0xE8 GMAC Interface Selection */
|
||||
volatile unsigned int rsvd6;/* 0xEC */
|
||||
volatile unsigned int eee; /* 0xF0 */
|
||||
volatile unsigned int revr; /* 0xF4 */
|
||||
volatile unsigned int fear; /* 0xF8 */
|
||||
volatile unsigned int rsvd7[1]; /* 0xFC */
|
||||
volatile unsigned int ptp_rx_addr; /* 0x100 PTP Destination Unicast IP Address on Rx path */
|
||||
volatile unsigned int ptp_tx_addr; /* 0x104 PTP Destination Unicast IP Address on Tx path */
|
||||
volatile unsigned int rsvd8[2]; /* 0x108 ~ 0x10C*/
|
||||
volatile unsigned int ptp_tx_sec; /* 0x110 PTP TX Event Frame Time-stamp for seconds */
|
||||
volatile unsigned int ptp_tx_nsec; /* 0x114 PTP TX Event Frame Time-stamp for nanoseconds */
|
||||
volatile unsigned int ptp_rx_sec; /* 0x118 PTP RX Event Frame Time-stamp for seconds */
|
||||
volatile unsigned int ptp_rx_nsec; /* 0x11C PTP RX Event Frame Time-stamp for nanoseconds */
|
||||
volatile unsigned int ptp_tx_p_sec; /* 0x120 PTP TX Peer Frame Time-stamp for seconds */
|
||||
volatile unsigned int ptp_tx_p_nsec; /* 0x124 PTP TX Peer Frame Time-stamp for nanoseconds */
|
||||
volatile unsigned int ptp_rx_p_sec; /* 0x128 PTP RX Peer Frame Time-stamp for seconds */
|
||||
volatile unsigned int ptp_rx_p_nsec; /* 0x12C PTP RX Peer Frame Time-stamp for nanoseconds */
|
||||
volatile unsigned int ptp_nnsec_tmr; /* 0x130 PTP Timer Nano-nansecond */
|
||||
volatile unsigned int ptp_nsec_tmr; /* 0x134 PTP Timer nanosecond */
|
||||
volatile unsigned int ptp_sec_tmr; /* 0x138 PTP Second */
|
||||
volatile unsigned int ptp_ns_period; /* 0x13C PTP period increment, max is 255 ns */
|
||||
volatile unsigned int ptp_nns_period; /* 0x140 PTP period increment, max is 0.999999999 ns */
|
||||
volatile unsigned int ptp_offset; /* 0x144 PTP period offset increment */
|
||||
volatile unsigned int ptp_tmr_adj; /* 0x148 PTP Timer Adjustment */
|
||||
};
|
||||
|
||||
/*
|
||||
* Interrupt Status Register 0x00 and 0x04
|
||||
*/
|
||||
#define FTGMAC030_INT_PDELAY_RESP_OUT (1 << 24)
|
||||
#define FTGMAC030_INT_PDELAY_RESP_IN (1 << 23)
|
||||
#define FTGMAC030_INT_PDELAY_REQ_OUT (1 << 22)
|
||||
#define FTGMAC030_INT_PDELAY_REQ_IN (1 << 21)
|
||||
#define FTGMAC030_INT_DELAY_REQ_OUT (1 << 20)
|
||||
#define FTGMAC030_INT_DELAY_REQ_IN (1 << 19)
|
||||
#define FTGMAC030_INT_SYNC_OUT (1 << 18)
|
||||
#define FTGMAC030_INT_SYNC_IN (1 << 17)
|
||||
#define FTGMAC030_INT_TSU_SEC_INC (1 << 16)
|
||||
#define FTGMAC030_INT_RX_LPI_IN (1 << 12)
|
||||
#define FTGMAC030_INT_RX_LPI_EXIT (1 << 11)
|
||||
#define FTGMAC030_INT_HPTXBUF_UNAVA (1 << 10)
|
||||
#define FTGMAC030_INT_PHYSTS_CHG (1 << 9)
|
||||
#define FTGMAC030_INT_AHB_ERR (1 << 8)
|
||||
#define FTGMAC030_INT_TPKT_LOST (1 << 7)
|
||||
#define FTGMAC030_INT_NPTXBUF_UNAVA (1 << 6)
|
||||
#define FTGMAC030_INT_TPKT2F (1 << 5)
|
||||
#define FTGMAC030_INT_TPKT2E (1 << 4)
|
||||
#define FTGMAC030_INT_RPKT_LOST (1 << 3)
|
||||
#define FTGMAC030_INT_RXBUF_UNAVA (1 << 2)
|
||||
#define FTGMAC030_INT_RPKT2F (1 << 1)
|
||||
#define FTGMAC030_INT_RPKT2B (1 << 0)
|
||||
|
||||
#define FTGMAC030_INT_DEFAULT ( \
|
||||
FTGMAC030_INT_RPKT2B | \
|
||||
FTGMAC030_INT_RXBUF_UNAVA | \
|
||||
FTGMAC030_INT_RPKT_LOST | \
|
||||
FTGMAC030_INT_TPKT2E | \
|
||||
FTGMAC030_INT_TPKT2F | \
|
||||
FTGMAC030_INT_TPKT_LOST | \
|
||||
FTGMAC030_INT_AHB_ERR | \
|
||||
FTGMAC030_INT_PHYSTS_CHG \
|
||||
)
|
||||
|
||||
#define FTGMAC030_INT_ALL ( \
|
||||
FTGMAC030_INT_RPKT2B | \
|
||||
FTGMAC030_INT_RPKT2F | \
|
||||
FTGMAC030_INT_RXBUF_UNAVA | \
|
||||
FTGMAC030_INT_RPKT_LOST | \
|
||||
FTGMAC030_INT_TPKT2E | \
|
||||
FTGMAC030_INT_TPKT2F | \
|
||||
FTGMAC030_INT_NPTXBUF_UNAVA | \
|
||||
FTGMAC030_INT_TPKT_LOST | \
|
||||
FTGMAC030_INT_AHB_ERR | \
|
||||
FTGMAC030_INT_PHYSTS_CHG | \
|
||||
FTGMAC030_INT_HPTXBUF_UNAVA \
|
||||
)
|
||||
/*
|
||||
* MAC Most Significant Address Register 0x08
|
||||
*/
|
||||
#define FTGMAC030_MADR(x) ((x & 0xffff) << 0)
|
||||
|
||||
/*
|
||||
* MAC Least Siginificant Address Register 0x0C
|
||||
*/
|
||||
#define FTGMAC030_LADR(x) ((x & 0xffffffff) << 0)
|
||||
|
||||
/*
|
||||
* TX Interrupt Timer Control Register 0x30
|
||||
*/
|
||||
#define FTGMAC030_TXITC_TIME_SEL (1 << 16)
|
||||
#define FTGMAC030_TXITC_CYL(x) ((x & 0xff) << 8)
|
||||
#define FTGMAC030_TXITC_THR(x) ((x & 0x7) << 4)
|
||||
#define FTGMAC030_TXITC_THR_UNIT(x) ((x & 0x3) << 0)
|
||||
|
||||
#define FTGMAC030_TXITC_DEFAULT FTGMAC030_TXITC_THR(1)
|
||||
|
||||
/*
|
||||
* RX Interrupt Timer Control Register 0x34
|
||||
*/
|
||||
#define FTGMAC030_RXITC_RST(x) ((x & 0xff) << 16)
|
||||
#define FTGMAC030_RXITC_TIME_SEL (1 << 16)
|
||||
#define FTGMAC030_RXITC_CYL(x) ((x & 0xff) << 8)
|
||||
#define FTGMAC030_RXITC_THR(x) ((x & 0x7) << 4)
|
||||
#define FTGMAC030_RXITC_THR_UNIT(x) ((x & 0x3) << 0)
|
||||
|
||||
#define FTGMAC030_RXITC_DEFAULT FTGMAC030_RXITC_THR(1)
|
||||
|
||||
/*
|
||||
* Automatic Polling Timer Control Register 0x34
|
||||
*/
|
||||
#define FTGMAC030_APTC_TX_TIME (1 << 12)
|
||||
#define FTGMAC030_APTC_TX_CNT(x) ((x & 0xf) << 8)
|
||||
#define FTGMAC030_APTC_RX_TIME (1 << 4)
|
||||
#define FTGMAC030_APTC_RX_CNT(x) ((x & 0xf) << 0)
|
||||
|
||||
#define FTGMAC030_APTC_DEFAULT FTGMAC030_APTC_RX_CNT(1)
|
||||
|
||||
/*
|
||||
* DMA Burst Length and Arbitration Control Register 0x38
|
||||
*/
|
||||
#define FTGMAC030_DBLAC_IFG_INC (1 << 23)
|
||||
#define FTGMAC030_DBLAC_IFG_CNT(x) ((x & 0x7) << 20)
|
||||
#define FTGMAC030_DBLAC_TXDES_SIZE(x) ((x & 0xf) << 16)
|
||||
#define FTGMAC030_DBLAC_RXDES_SIZE(x) ((x & 0xf) << 12)
|
||||
#define FTGMAC030_DBLAC_TXBST_SIZE(x) ((x & 0x3) << 10)
|
||||
#define FTGMAC030_DBLAC_RXBST_SIZE(x) ((x & 0x3) << 8)
|
||||
#define FTGMAC030_DBLAC_RX_THR_EN (1 << 6)
|
||||
#define FTGMAC030_DBLAC_RXFIFO_HTHR(x) ((x & 0x7) << 3)
|
||||
#define FTGMAC030_DBLAC_RXFIFO_LTHR(x) ((x & 0x7) << 0)
|
||||
|
||||
#define FTGMAC030_DBLAC_DEFAULT FTGMAC030_DBLAC_RXFIFO_LTHR(2) | \
|
||||
FTGMAC030_DBLAC_RXFIFO_HTHR(6) | \
|
||||
FTGMAC030_DBLAC_RX_THR_EN | \
|
||||
FTGMAC030_DBLAC_RXBST_SIZE(3) | \
|
||||
FTGMAC030_DBLAC_TXBST_SIZE(3)
|
||||
/*
|
||||
* DMA/FIFO State Register 0x3c
|
||||
*/
|
||||
#define FTGMAC030_DMAFIFOS_TXD_REQ (1 << 31)
|
||||
#define FTGMAC030_DMAFIFOS_RXD_REQ (1 << 30)
|
||||
#define FTGMAC030_DMAFIFOS_DARB_TXGNT (1 << 29)
|
||||
#define FTGMAC030_DMAFIFOS_DARB_RXGNT (1 << 28)
|
||||
#define FTGMAC030_DMAFIFOS_TXFIFO_EMPTY (1 << 27)
|
||||
#define FTGMAC030_DMAFIFOS_RXFIFO_EMPTY (1 << 26)
|
||||
#define FTGMAC030_DMAFIFOS_TXDMA3_SM(x) ((x & 0xf) << 18)
|
||||
#define FTGMAC030_DMAFIFOS_TXDMA2_SM(x) ((x & 0xf) << 16)
|
||||
#define FTGMAC030_DMAFIFOS_TXDMA1_SM(x) ((x & 0xf) << 12)
|
||||
#define FTGMAC030_DMAFIFOS_RXDMA3_SM(x) ((x & 0xf) << 8)
|
||||
#define FTGMAC030_DMAFIFOS_RXDMA2_SM(x) ((x & 0xf) << 4)
|
||||
#define FTGMAC030_DMAFIFOS_RXDMA1_SM(x) ((x & 0xf) << 0)
|
||||
|
||||
/*
|
||||
* Revision Register 0x40
|
||||
*/
|
||||
#define FTGMAC030_REV_B1(x) ((x >> 16) & 0xff)
|
||||
#define FTGMAC030_REV_B2(x) ((x >> 8) & 0xff)
|
||||
#define FTGMAC030_REV_B3(x) (x & 0xff)
|
||||
|
||||
/*
|
||||
* Feature Register 0xF8
|
||||
*/
|
||||
#define FTGMAC030_FEAR_TFIFO_RSIZE(x) ((x & 0x7) >> 4)
|
||||
#define FTGMAC030_FEAR_RFIFO_RSIZE(x) ((x & 0x7) >> 0)
|
||||
|
||||
/*
|
||||
* Transmit Priority Arbitration and FIFO Control Register 0x48
|
||||
*/
|
||||
#define FTGMAC030_TPAFCR_TFIFO_SIZE(x) ((x & 0x7) << 27)
|
||||
#define FTGMAC030_TPAFCR_RFIFO_SIZE(x) ((x & 0x7) << 24)
|
||||
#define FTGMAC030_TPAFCR_EARLY_TXTHR(x) ((x & 0xff) << 16)
|
||||
#define FTGMAC030_TPAFCR_EARLY_RXTHR(x) ((x & 0xff) << 8)
|
||||
#define FTGMAC030_TPAFCR_HPKT_THR(x) ((x & 0xf) << 4)
|
||||
#define FTGMAC030_TPAFCR_NPKT_THR(x) ((x & 0xf) << 0)
|
||||
|
||||
/*
|
||||
* Receive Buffer Size Register 0x4c
|
||||
*/
|
||||
#define FTGMAC030_RBSR_RXBUF_SIZE(x) ((x & 0x3fff) << 0)
|
||||
|
||||
/*
|
||||
* MAC Control Register 0x50
|
||||
*/
|
||||
#define FTGMAC030_MACCR_SW_RST (1 << 31)
|
||||
#define FTGMAC030_MACCR_FULLDUP (1 << 26)
|
||||
#define FTGMAC030_MACCR_SPEED_MASK (0x3 << 24)
|
||||
#define FTGMAC030_MACCR_SPEED_1000 (2 << 24)
|
||||
#define FTGMAC030_MACCR_SPEED_100 (1 << 24)
|
||||
#define FTGMAC030_MACCR_SPEED_10 (0 << 24)
|
||||
#define FTGMAC030_MACCR_HPTXR (1 << 22)
|
||||
#define FTGMAC030_MACCR_LOOPBACK (1 << 21)
|
||||
#define FTGMAC030_MACCR_PTP_EN (1 << 20)
|
||||
#define FTGMAC030_MACCR_REMOVE_VLAN (1 << 18)
|
||||
#define FTGMAC030_MACCR_CRC_APD (1 << 17)
|
||||
#define FTGMAC030_MACCR_DROP_CRC_ERR (1 << 16)
|
||||
#define FTGMAC030_MACCR_ENRX_IN_HALFTX (1 << 14)
|
||||
#define FTGMAC030_MACCR_JUMBO_LF (1 << 13)
|
||||
#define FTGMAC030_MACCR_RX_RUNT (1 << 12)
|
||||
#define FTGMAC030_MACCR_BROADPKT (1 << 11)
|
||||
#define FTGMAC030_MACCR_MULTIPKT (1 << 10)
|
||||
#define FTGMAC030_MACCR_HT_EN (1 << 9)
|
||||
#define FTGMAC030_MACCR_ALLADDR (1 << 8)
|
||||
#define FTGMAC030_MACCR_RXMAC (1 << 3)
|
||||
#define FTGMAC030_MACCR_TXMAC (1 << 2)
|
||||
#define FTGMAC030_MACCR_RXDMA (1 << 1)
|
||||
#define FTGMAC030_MACCR_TXDMA (1 << 0)
|
||||
|
||||
#define FTGMAC030_MACCR_DEFAULT ( \
|
||||
FTGMAC030_MACCR_RX_RUNT | \
|
||||
FTGMAC030_MACCR_CRC_APD | \
|
||||
FTGMAC030_MACCR_FULLDUP | \
|
||||
FTGMAC030_MACCR_TXDMA | \
|
||||
FTGMAC030_MACCR_RXMAC | \
|
||||
FTGMAC030_MACCR_RXDMA | \
|
||||
FTGMAC030_MACCR_TXMAC)
|
||||
|
||||
/*
|
||||
* MAC Status Register 0x54
|
||||
*/
|
||||
#define FTGMAC030_MACSR_COL_EXCEED
|
||||
#define FTGMAC030_MACSR_LATE_COL
|
||||
#define FTGMAC030_MACSR_XPKT_LOST
|
||||
#define FTGMAC030_MACSR_XPKT_OK
|
||||
#define FTGMAC030_MACSR_RUNT
|
||||
#define FTGMAC030_MACSR_FTL
|
||||
#define FTGMAC030_MACSR_CRC_ERR
|
||||
#define FTGMAC030_MACSR_RPKT_LOST
|
||||
#define FTGMAC030_MACSR_RPKT_SAVE
|
||||
#define FTGMAC030_MACSR_COL
|
||||
#define FTGMAC030_MACSR_BROADCAST
|
||||
#define FTGMAC030_MACSR_MULTICAST
|
||||
|
||||
/*
|
||||
* Test Mode Register 0x58
|
||||
*/
|
||||
#define FTGMAC030_TM_PTIMER_TEST (1 << 20)
|
||||
#define FTGMAC030_TM_ITIMER_TEST (1 << 19)
|
||||
#define FTGMAC030_TM_TEST_COL (1 << 15)
|
||||
#define FTGMAC030_TM_TEST_BKOFF(x) ((x & 0x3ff) << 5)
|
||||
#define FTGMAC030_TM_TEST_EXSTHR(x) ((x & 0x1f) << 0)
|
||||
|
||||
/*
|
||||
* PHY Control Register 0x60
|
||||
*/
|
||||
#define FTGMAC030_MDIO_SOF 1
|
||||
#define FTGMAC030_MDIO_EXT_SOF 0
|
||||
#define FTGMAC030_MDIO_OP_RD 2
|
||||
#define FTGMAC030_MDIO_OP_WR 1
|
||||
|
||||
#define FTGMAC030_PHYCR_PHYWR (1 << 27)
|
||||
#define FTGMAC030_PHYCR_PHYRD (1 << 26)
|
||||
#define FTGMAC030_PHYCR_REGAD(x) ((x & 0x1f) << 21)
|
||||
#define FTGMAC030_PHYCR_PHYAD(x) ((x & 0x1f) << 16)
|
||||
#define FTGMAC030_PHYCR_OP(x) ((x & 0x3) << 14)
|
||||
#define FTGMAC030_PHYCR_SOF(x) ((x & 0x3) << 12)
|
||||
|
||||
#define FTGMAC030_PHYCR_MDC_CYCTHR(x) ((x) & 0xff)
|
||||
#define FTGMAC030_PHYCR_MDC_CYCTHR_MASK 0xff
|
||||
|
||||
/*
|
||||
* PHY Data Register 0x64
|
||||
*/
|
||||
#define FTGMAC030_PHYDATA_MIIRDATA(x) ((x & 0xffff0000) >> 16)
|
||||
#define FTGMAC030_PHYDATA_MIIWDATA(x) ((x & 0xffff) >> 0)
|
||||
|
||||
/*
|
||||
* Flow Control Register 0x68
|
||||
*/
|
||||
#define FTGMAC030_FCR_PAUSE_TIME(x) ((x & 0xffff) << 16)
|
||||
#define FTGMAC030_FCR_FC_H_L(x) ((x & 0x7f) << 9)
|
||||
#define FTGMAC030_FCR_HTHR (1 << 8)
|
||||
#define FTGMAC030_FCR_RX_PAUSE (1 << 4)
|
||||
#define FTGMAC030_FCR_TXPAUSED (1 << 3)
|
||||
#define FTGMAC030_FCR_FCTHR_EN (1 << 2)
|
||||
#define FTGMAC030_FCR_TX_PAUSE (1 << 1)
|
||||
#define FTGMAC030_FCR_FC_EN (1 << 0)
|
||||
|
||||
/*
|
||||
* Back Pressure Register 0x6c
|
||||
*/
|
||||
#define ftgmac030_BPR_BK_LOW(x) ((x & 0x7f) << 8)
|
||||
#define ftgmac030_BPR_BKJAM_LEN(x) ((x & 0xf) << 4)
|
||||
#define ftgmac030_BPR_BKADR_MODE (1 << 1)
|
||||
#define ftgmac030_BPR_BKEN (1 << 0)
|
||||
|
||||
/*
|
||||
* Wake-On-LAN Control Register 0x70
|
||||
*/
|
||||
#define FTGMAC030_WOLCR_WOL_TYPE(x) ((x & 0x3) << 24)
|
||||
#define FTGMAC030_WOLCR_SW_PDNPHY (1 << 18)
|
||||
#define FTGMAC030_WOLCR_WAKEUP_SEL(x) ((x & 0x3) << 16)
|
||||
#define FTGMAC030_WOLCR_WAKEUP4 (1 << 6)
|
||||
#define FTGMAC030_WOLCR_WAKEUP3 (1 << 5)
|
||||
#define FTGMAC030_WOLCR_WAKEUP2 (1 << 4)
|
||||
#define FTGMAC030_WOLCR_WAKEUP1 (1 << 3)
|
||||
#define FTGMAC030_WOLCR_MAGICPKT (1 << 2)
|
||||
#define FTGMAC030_WOLCR_LINKCHG1 (1 << 1)
|
||||
#define FTGMAC030_WOLCR_LINKCHG0 (1 << 0)
|
||||
|
||||
/*
|
||||
* Wake-On-LAN Status Register 0x74
|
||||
*/
|
||||
#define FTGMAC030_WOLSR_WAKEUP4 (1 << 6)
|
||||
#define FTGMAC030_WOLSR_WAKEUP3 (1 << 5)
|
||||
#define FTGMAC030_WOLSR_WAKEUP2 (1 << 4)
|
||||
#define FTGMAC030_WOLSR_WAKEUP1 (1 << 3)
|
||||
#define FTGMAC030_WOLSR_MAGICPKT (1 << 2)
|
||||
#define FTGMAC030_WOLSR_LINKCHG1 (1 << 1)
|
||||
#define FTGMAC030_WOLSR_LINKCHG0 (1 << 0)
|
||||
|
||||
/*
|
||||
* Transmit descriptor, aligned to 16 bytes
|
||||
*/
|
||||
struct ftgmac030_txdes {
|
||||
volatile unsigned int txdes0;
|
||||
volatile unsigned int txdes1;
|
||||
volatile unsigned int txdes2; /* not used by HW */
|
||||
volatile unsigned int txdes3; /* TXBUF_BADR */
|
||||
} __attribute__ ((aligned(16)));
|
||||
|
||||
#define FTGMAC030_TXDES0_TXDMA_OWN (1 << 31)
|
||||
#define FTGMAC030_TXDES0_FTS (1 << 29)
|
||||
#define FTGMAC030_TXDES0_LTS (1 << 28)
|
||||
#define FTGMAC030_TXDES0_CRC_ERR (1 << 19)
|
||||
#define FTGMAC030_TXDES0_EDOTR (1 << 15)
|
||||
#define FTGMAC030_TXDES0_BUF_SIZE(x) ((x & 0x3fff) << 0)
|
||||
|
||||
#define FTGMAC030_TXDES1_TXIC (1 << 31)
|
||||
#define FTGMAC030_TXDES1_TX2FIC (1 << 30)
|
||||
#define FTGMAC030_TXDES1_LLC_PKT (1 << 22)
|
||||
#define FTGMAC030_TXDES1_IPV6_PKT (1 << 20)
|
||||
#define FTGMAC030_TXDES1_OTHER_PKT (2 << 20)
|
||||
#define FTGMAC030_TXDES1_IPCS_EN (1 << 19)
|
||||
#define FTGMAC030_TXDES1_UDPCS_EN (1 << 18)
|
||||
#define FTGMAC030_TXDES1_TCPCS_EN (1 << 17)
|
||||
#define FTGMAC030_TXDES1_INS_VLAN (1 << 16)
|
||||
#define FTGMAC030_TXDES1_VLAN_TAGC(x) ((x & 0xffff) << 0)
|
||||
|
||||
#define FTGMAC030_TXDES1_DEFAULT (FTGMAC030_TXDES1_TXIC | FTGMAC030_TXDES1_TX2FIC)
|
||||
|
||||
/*
|
||||
* Receive descriptor, aligned to 16 bytes
|
||||
*/
|
||||
struct ftgmac030_rxdes {
|
||||
volatile unsigned int rxdes0;
|
||||
volatile unsigned int rxdes1;
|
||||
volatile unsigned int rxdes2; /* not used by HW */
|
||||
volatile unsigned int rxdes3; /* RXBUF_BADR */
|
||||
} __attribute__ ((aligned(16)));
|
||||
|
||||
#define FTGMAC030_RXDES0_RXPKT_RDY (1 << 31)
|
||||
#define FTGMAC030_RXDES0_FRS (1 << 29)
|
||||
#define FTGMAC030_RXDES0_LRS (1 << 28)
|
||||
#define FTGMAC030_RXDES0_PAUSE_FRAME (1 << 25)
|
||||
#define FTGMAC030_RXDES0_PAUSE_OPCODE (1 << 24)
|
||||
#define FTGMAC030_RXDES0_FIFO_FULL (1 << 23)
|
||||
#define FTGMAC030_RXDES0_RX_ODD_NB (1 << 22)
|
||||
#define FTGMAC030_RXDES0_RUNT (1 << 21)
|
||||
#define FTGMAC030_RXDES0_FTL (1 << 20)
|
||||
#define FTGMAC030_RXDES0_CRC_ERR (1 << 19)
|
||||
#define FTGMAC030_RXDES0_RX_ERR (1 << 18)
|
||||
#define FTGMAC030_RXDES0_BROADCAST (1 << 17)
|
||||
#define FTGMAC030_RXDES0_MULTICAST (1 << 16)
|
||||
#define FTGMAC030_RXDES0_EDORR (1 << 15)
|
||||
#define FTGMAC030_RXDES0_VDBC(x) ((x & 0x3fff) << 0)
|
||||
|
||||
#define FTGMAC030_RXDES1_IPCS_FAIL (1 << 27)
|
||||
#define FTGMAC030_RXDES1_UDPCS_FAIL (1 << 26)
|
||||
#define FTGMAC030_RXDES1_TCPCS_FAIL (1 << 25)
|
||||
#define FTGMAC030_RXDES1_VLAN_AVA (1 << 24)
|
||||
#define FTGMAC030_RXDES1_DF (1 << 23)
|
||||
#define FTGMAC030_RXDES1_LLC_PKT (1 << 22)
|
||||
#define FTGMAC030_RXDES1_PROTL_TYPE(x) ((x >> 20) & 0x3)
|
||||
#define FTGMAC030_RXDES1_IP6_TYPE(x) ((x >> 19) & 0x1)
|
||||
#define FTGMAC030_RXDES1_VLAN_PRIO(x) ((x & 7) << 13)
|
||||
#define FTGMAC030_RXDES1_VLAN_CFI(x) ((x & 1) << 12)
|
||||
#define FTGMAC030_RXDES1_VLAN_VID(x) (x & 0x0fff)
|
||||
#define FTGMAC030_RXDES1_VLAN_TAGC(x) (x & 0xffff)
|
||||
|
||||
#define FTGMAC030_RXDES1_PROT_MASK (0x3 << 20)
|
||||
#define FTGMAC030_RXDES1_PROTL_NOTIP 0
|
||||
#define FTGMAC030_RXDES1_PROTL_IP4 1
|
||||
#define FTGMAC030_RXDES1_PROTL_TCPIP 2
|
||||
#define FTGMAC030_RXDES1_PROTL_UDPIP 3
|
||||
|
||||
/* 0:MII or GMII,(don't suport) 1:RMII, 2: RGMII */
|
||||
enum ftgmac030_if_mode {
|
||||
FTGMAC030_MODE_MII_GMII,
|
||||
FTGMAC030_MODE_RMII,
|
||||
FTGMAC030_MODE_RGMII,
|
||||
};
|
||||
|
||||
int ftgmac030_mdio_read(struct eth_device *dev, int phy_addr, int regnum);
|
||||
int ftgmac030_mdio_write(struct eth_device *dev, int phy_addr, int regnum, u16 value);
|
||||
|
||||
#endif /* __FTGMAC030_H */
|
||||
@@ -0,0 +1,611 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//#define DEBUG
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <wait_bit.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <cpu_func.h>
|
||||
#include <miiphy.h>
|
||||
#include <hexdump.h>
|
||||
|
||||
#include "ftgmac030.h"
|
||||
#include "sys.h"
|
||||
|
||||
#define ETH_ZLEN 60
|
||||
|
||||
/* Receive Buffer Size Register - HW default is 0x640 */
|
||||
#define FTGMAC030_RBSR_DEFAULT_VALUE 0x640
|
||||
|
||||
/* PKTBUFSTX/PKTBUFSRX must both be power of 2 */
|
||||
#define FTGMAC030_PKTBUFSTX 4 /* must be power of 2 */
|
||||
#define FTGMAC030_PKTBUFSRX PKTBUFSRX /* must be power of 2 */
|
||||
|
||||
/* Timeout for transmit */
|
||||
#define FTGMAC030_TX_TIMEOUT_MS 1000
|
||||
|
||||
/* Timeout for a mdio read/write operation */
|
||||
#define FTGMAC030_MDIO_TIMEOUT_USEC 10000
|
||||
|
||||
#define MAC_LEN 6
|
||||
|
||||
struct ftgmac030_data {
|
||||
struct ftgmac030_txdes txdes[FTGMAC030_PKTBUFSTX] __aligned(ARCH_DMA_MINALIGN);
|
||||
struct ftgmac030_rxdes rxdes[FTGMAC030_PKTBUFSRX] __aligned(ARCH_DMA_MINALIGN);
|
||||
char rsvd1[0] __aligned(ARCH_DMA_MINALIGN);
|
||||
int tx_index;
|
||||
int rx_index;
|
||||
int phy_addr;
|
||||
enum ftgmac030_if_mode phy_intf;
|
||||
struct mii_dev *bus;
|
||||
struct phy_device *phydev;
|
||||
u32 max_speed;
|
||||
u8 mdc_cycthr;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct mdio functions
|
||||
*/
|
||||
int ftgmac030_mdio_read(struct eth_device *dev, int phy_addr,
|
||||
int regnum)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
int phycr;
|
||||
int data;
|
||||
int ret;
|
||||
|
||||
phycr = FTGMAC030_PHYCR_PHYAD(phy_addr)
|
||||
| FTGMAC030_PHYCR_REGAD(regnum)
|
||||
| FTGMAC030_PHYCR_OP(FTGMAC030_MDIO_OP_RD)
|
||||
| FTGMAC030_PHYCR_SOF(FTGMAC030_MDIO_SOF)
|
||||
| FTGMAC030_PHYCR_PHYRD
|
||||
| priv->mdc_cycthr;
|
||||
|
||||
writel(phycr, &ftgmac030->phycr);
|
||||
|
||||
ret = readl_poll_timeout(&ftgmac030->phycr, phycr,
|
||||
!(phycr & FTGMAC030_PHYCR_PHYRD),
|
||||
FTGMAC030_MDIO_TIMEOUT_USEC);
|
||||
if (ret) {
|
||||
pr_err("mdio read failed (phy:%d reg:%x)\n", phy_addr, regnum);
|
||||
return ret;
|
||||
}
|
||||
|
||||
data = readl(&ftgmac030->phydata);
|
||||
|
||||
return FTGMAC030_PHYDATA_MIIRDATA(data);
|
||||
}
|
||||
|
||||
int ftgmac030_mdio_write(struct eth_device *dev, int phy_addr,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
int phycr;
|
||||
int data;
|
||||
int ret;
|
||||
|
||||
phycr = FTGMAC030_PHYCR_PHYAD(phy_addr)
|
||||
| FTGMAC030_PHYCR_REGAD(regnum)
|
||||
| FTGMAC030_PHYCR_OP(FTGMAC030_MDIO_OP_WR)
|
||||
| FTGMAC030_PHYCR_SOF(FTGMAC030_MDIO_SOF)
|
||||
| FTGMAC030_PHYCR_PHYWR
|
||||
| priv->mdc_cycthr;
|
||||
|
||||
data = FTGMAC030_PHYDATA_MIIWDATA(value);
|
||||
|
||||
writel(data, &ftgmac030->phydata);
|
||||
writel(phycr, &ftgmac030->phycr);
|
||||
|
||||
ret = readl_poll_timeout(&ftgmac030->phycr, phycr,
|
||||
!(phycr & FTGMAC030_PHYCR_PHYWR),
|
||||
FTGMAC030_MDIO_TIMEOUT_USEC);
|
||||
if (ret)
|
||||
pr_err("mdio write failed (phy:%d reg:%x)\n", phy_addr, regnum);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* MDIO Bus Interface */
|
||||
static int ftgmac030_mdiobus_read(struct mii_dev *bus, int addr, int devad, int reg)
|
||||
{
|
||||
struct eth_device *dev = (struct eth_device *)bus->priv;
|
||||
|
||||
return ftgmac030_mdio_read(dev, addr, reg);
|
||||
}
|
||||
|
||||
static int ftgmac030_mdiobus_write(struct mii_dev *bus, int addr, int devad,
|
||||
int reg, u16 value)
|
||||
{
|
||||
struct eth_device *dev = (struct eth_device *)bus->priv;
|
||||
|
||||
return ftgmac030_mdio_write(dev, addr, reg, value);
|
||||
}
|
||||
|
||||
static void ftgmac030_set_phy_intf(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
|
||||
priv->phy_intf = bspeth_get_phy_intf();
|
||||
|
||||
printf("%s (%s)\n", __func__, (priv->phy_intf == FTGMAC030_MODE_MII_GMII) ?
|
||||
"mii" : ((priv->phy_intf == FTGMAC030_MODE_RMII) ? "rmii" : "rgmii"));
|
||||
|
||||
writel(priv->phy_intf, &ftgmac030->gisr);
|
||||
|
||||
if (priv->phy_intf == FTGMAC030_MODE_RGMII) {
|
||||
/* Set rgmii tx delay for 2ns */
|
||||
bspeth_set_tx_delay();
|
||||
}
|
||||
|
||||
/* set the mdc cycthr sys_clk mpw:200M pliot:297*/
|
||||
priv->mdc_cycthr = 0xc8;
|
||||
|
||||
/* update max_speed*/
|
||||
priv->max_speed = (priv->phy_intf == FTGMAC030_MODE_RGMII) ?
|
||||
SPEED_1000 : SPEED_100;
|
||||
|
||||
/* update phy_intf to libphy */
|
||||
priv->phy_intf = (priv->phy_intf == FTGMAC030_MODE_MII_GMII) ?
|
||||
PHY_INTERFACE_MODE_MII : ((priv->phy_intf == FTGMAC030_MODE_RMII) ?
|
||||
PHY_INTERFACE_MODE_RMII :PHY_INTERFACE_MODE_RGMII_RXID);
|
||||
|
||||
}
|
||||
|
||||
int ftgmac030_mdiobus_init(struct eth_device *dev)
|
||||
{
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
struct mii_dev *bus = mdio_alloc();
|
||||
|
||||
if (!bus) {
|
||||
printf("Failed to allocate MDIO bus\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bus->priv = dev;
|
||||
bus->read = ftgmac030_mdiobus_read;
|
||||
bus->write = ftgmac030_mdiobus_write;
|
||||
snprintf(bus->name, sizeof(bus->name), dev->name);
|
||||
|
||||
if (mdio_register(bus)) {
|
||||
mdio_free(bus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
miiphy_set_current_dev(dev->name);
|
||||
|
||||
priv->bus = bus;
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftgmac030_phy_init(struct eth_device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
struct phy_device *phydev;
|
||||
|
||||
int phy_addr;
|
||||
u32 phy_id;
|
||||
|
||||
/* Check if the PHY is up to snuff... */
|
||||
for (phy_addr = 0; phy_addr < 32; phy_addr++) {
|
||||
phy_id = ftgmac030_mdio_read(dev, phy_addr, MII_PHYSID1);
|
||||
/*
|
||||
* When it is unable to found PHY,
|
||||
* the interface usually return 0xffff or 0x0000
|
||||
*/
|
||||
if (phy_id != 0xffff && phy_id != 0x0) {
|
||||
|
||||
priv->phy_addr = phy_addr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (phy_id == 0xffff || phy_id == 0x0) {
|
||||
printf("%s: no PHY present\n", dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy_id = ((phy_id & 0xffff) << 16) |
|
||||
ftgmac030_mdio_read(dev, phy_addr, MII_PHYSID2);
|
||||
|
||||
printf("%s: found PHY(0x%x) at 0x%02x\n",
|
||||
dev->name, phy_id, phy_addr);
|
||||
|
||||
phydev = phy_connect(priv->bus, priv->phy_addr, dev, priv->phy_intf);
|
||||
if (!phydev)
|
||||
return -ENODEV;
|
||||
|
||||
printf("%s connected to %s\n", dev->name, phydev->drv->name);
|
||||
|
||||
phydev->supported &= PHY_GBIT_FEATURES;
|
||||
|
||||
if (priv->max_speed) {
|
||||
ret = phy_set_supported(phydev, priv->max_speed);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
phydev->advertising = phydev->supported;
|
||||
priv->phydev = phydev;
|
||||
phy_config(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftgmac030_phy_link_speed(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
struct phy_device *phydev = priv->phydev;
|
||||
unsigned int maccr;
|
||||
|
||||
if (!phydev->link) {
|
||||
dev_err(phydev->dev, "No link\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
/* read MAC control register and clear related bits */
|
||||
maccr = readl(&ftgmac030->maccr) &
|
||||
~(FTGMAC030_MACCR_SPEED_1000 |
|
||||
FTGMAC030_MACCR_SPEED_100 |
|
||||
FTGMAC030_MACCR_FULLDUP);
|
||||
|
||||
if (phy_interface_is_rgmii(phydev) && phydev->speed == 1000)
|
||||
maccr |= FTGMAC030_MACCR_SPEED_1000;
|
||||
|
||||
if (phydev->speed == 100)
|
||||
maccr |= FTGMAC030_MACCR_SPEED_100;
|
||||
|
||||
if (phydev->duplex)
|
||||
maccr |= FTGMAC030_MACCR_FULLDUP;
|
||||
|
||||
/* update MII config into maccr */
|
||||
writel(maccr, &ftgmac030->maccr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset MAC
|
||||
*/
|
||||
static void ftgmac030_reset(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
|
||||
debug("%s()\n", __func__);
|
||||
|
||||
writel(FTGMAC030_MACCR_SW_RST, &ftgmac030->maccr);
|
||||
|
||||
while (readl(&ftgmac030->maccr) & FTGMAC030_MACCR_SW_RST)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set MAC address
|
||||
*/
|
||||
static void ftgmac030_set_mac(struct eth_device *dev,
|
||||
const unsigned char *mac)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
unsigned int maddr = mac[0] << 8 | mac[1];
|
||||
unsigned int laddr = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5];
|
||||
|
||||
debug("%s(%x %x)\n", __func__, maddr, laddr);
|
||||
|
||||
writel(maddr, &ftgmac030->mac_madr);
|
||||
writel(laddr, &ftgmac030->mac_ladr);
|
||||
}
|
||||
|
||||
static void ftgmac030_set_mac_from_env(struct eth_device *dev)
|
||||
{
|
||||
unsigned char mac[MAC_LEN];
|
||||
|
||||
memset(mac, 0, sizeof(mac));
|
||||
|
||||
if (!eth_env_get_enetaddr("ethaddr", mac)) {
|
||||
printf("MAC address invalid!\n");
|
||||
#ifdef CONFIG_NET_RANDOM_ETHADDR
|
||||
net_random_ethaddr(mac);
|
||||
printf("Set Random MAC address!\n");
|
||||
eth_env_set_enetaddr("ethaddr", mac);
|
||||
#endif
|
||||
}
|
||||
|
||||
memcpy(dev->enetaddr, mac, MAC_LEN);
|
||||
|
||||
ftgmac030_set_mac(dev, dev->enetaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* disable transmitter, receiver
|
||||
*/
|
||||
static void ftgmac030_halt(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
|
||||
debug("%s()\n", __func__);
|
||||
|
||||
writel(0, &ftgmac030->maccr);
|
||||
|
||||
bspeth_sys_exit();
|
||||
}
|
||||
|
||||
static int ftgmac030_init(struct eth_device *dev, bd_t *bd)
|
||||
{
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
struct phy_device *phydev = priv->phydev;
|
||||
unsigned int maccr;
|
||||
ulong start, end;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
debug("%s()\n", __func__);
|
||||
|
||||
if (phydev == NULL) {
|
||||
/* sys-func-sel */
|
||||
bspeth_sys_init();
|
||||
|
||||
/* set the MII interface */
|
||||
ftgmac030_set_phy_intf(dev);
|
||||
|
||||
ftgmac030_mdiobus_init(dev);
|
||||
|
||||
ret = ftgmac030_phy_init(dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to initialize PHY\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
phydev = priv->phydev;
|
||||
}
|
||||
|
||||
ftgmac030_reset(dev);
|
||||
|
||||
/* set the ethernet address */
|
||||
ftgmac030_set_mac_from_env(dev);
|
||||
|
||||
/* disable all interrupts */
|
||||
writel(0, &ftgmac030->ier);
|
||||
|
||||
/* initialize descriptors */
|
||||
priv->tx_index = 0;
|
||||
priv->rx_index = 0;
|
||||
|
||||
for (i = 0; i < FTGMAC030_PKTBUFSTX; i++) {
|
||||
/* TXBUF_BADR */
|
||||
priv->txdes[i].txdes3 = 0;
|
||||
priv->txdes[i].txdes0 = 0;
|
||||
}
|
||||
priv->txdes[FTGMAC030_PKTBUFSTX - 1].txdes0 = FTGMAC030_TXDES0_EDOTR;
|
||||
|
||||
start = ((ulong)&priv->txdes[0]) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
end = start + roundup(sizeof(priv->txdes), ARCH_DMA_MINALIGN);
|
||||
flush_dcache_range(start, end);
|
||||
|
||||
for (i = 0; i < FTGMAC030_PKTBUFSRX; i++) {
|
||||
/* RXBUF_BADR */
|
||||
priv->rxdes[i].rxdes3 = (unsigned int)net_rx_packets[i];
|
||||
priv->rxdes[i].rxdes0 = 0;
|
||||
}
|
||||
priv->rxdes[FTGMAC030_PKTBUFSRX - 1].rxdes0 = FTGMAC030_RXDES0_EDORR;
|
||||
|
||||
start = ((ulong)&priv->rxdes[0]) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
end = start + roundup(sizeof(priv->rxdes), ARCH_DMA_MINALIGN);
|
||||
flush_dcache_range(start, end);
|
||||
|
||||
/* transmit ring */
|
||||
writel((unsigned int)priv->txdes, &ftgmac030->nptxdesc_addr);
|
||||
|
||||
/* receive ring */
|
||||
writel((unsigned int)priv->rxdes, &ftgmac030->rxdesc_addr);
|
||||
|
||||
/* poll receive descriptor automatically */
|
||||
writel(FTGMAC030_APTC_DEFAULT, &ftgmac030->aptc);
|
||||
|
||||
/* config receive buffer size register */
|
||||
writel(FTGMAC030_RBSR_RXBUF_SIZE(FTGMAC030_RBSR_DEFAULT_VALUE), &ftgmac030->rbsr);
|
||||
|
||||
/* enable transmitter, receiver */
|
||||
maccr = FTGMAC030_MACCR_DEFAULT;
|
||||
writel(maccr, &ftgmac030->maccr);
|
||||
|
||||
|
||||
ret = phy_startup(phydev);
|
||||
if (ret) {
|
||||
dev_err(phydev->dev, "Could not start PHY\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ftgmac030_phy_link_speed(dev);
|
||||
if (ret) {
|
||||
dev_err(phydev->dev, "Could not adjust link\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("%s: link up, %d Mbps %s-duplex\n", phydev->dev->name,
|
||||
phydev->speed, phydev->duplex ? "full" : "half");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a data block via Ethernet
|
||||
*/
|
||||
static int ftgmac030_recv(struct eth_device *dev)
|
||||
{
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
struct ftgmac030_rxdes *curr_des = &priv->rxdes[priv->rx_index];
|
||||
unsigned short rxlen;
|
||||
ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
ulong des_end = des_start +
|
||||
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
|
||||
ulong data_start = curr_des->rxdes3;
|
||||
ulong data_end;
|
||||
|
||||
invalidate_dcache_range(des_start, des_end);
|
||||
|
||||
if (!(curr_des->rxdes0 & FTGMAC030_RXDES0_RXPKT_RDY))
|
||||
return -EAGAIN;
|
||||
|
||||
if (curr_des->rxdes0 & (FTGMAC030_RXDES0_RX_ERR |
|
||||
FTGMAC030_RXDES0_CRC_ERR |
|
||||
FTGMAC030_RXDES0_FTL |
|
||||
FTGMAC030_RXDES0_RUNT |
|
||||
FTGMAC030_RXDES0_RX_ODD_NB)) {
|
||||
if (curr_des->rxdes0 & FTGMAC030_RXDES0_CRC_ERR) {
|
||||
genphy_restart_aneg(priv->phydev);
|
||||
genphy_update_link(priv->phydev);
|
||||
}
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
rxlen = FTGMAC030_RXDES0_VDBC(curr_des->rxdes0);
|
||||
|
||||
debug("%s(): RX buffer %d, %x received(%x)\n",
|
||||
__func__, priv->rx_index, rxlen, curr_des->rxdes3);
|
||||
|
||||
/* Invalidate received data */
|
||||
data_end = data_start + roundup(rxlen, ARCH_DMA_MINALIGN);
|
||||
invalidate_dcache_range(data_start, data_end);
|
||||
|
||||
/* pass the packet up to the protocol layers. */
|
||||
net_process_received_packet((void *)curr_des->rxdes3, rxlen);
|
||||
|
||||
/* Release buffer to DMA*/
|
||||
curr_des->rxdes0 &= FTGMAC030_RXDES0_EDORR;
|
||||
curr_des->rxdes1 = 0x0;
|
||||
flush_dcache_range(des_start, des_end);
|
||||
|
||||
/* Move to next descriptor */
|
||||
priv->rx_index = (priv->rx_index + 1) % FTGMAC030_PKTBUFSRX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 ftgmac030_read_txdesc(const void *desc)
|
||||
{
|
||||
const struct ftgmac030_txdes *txdes = desc;
|
||||
ulong des_start = ((ulong)txdes) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
ulong des_end = des_start +
|
||||
roundup(sizeof(*txdes), ARCH_DMA_MINALIGN);
|
||||
|
||||
invalidate_dcache_range(des_start, des_end);
|
||||
|
||||
return txdes->txdes0;
|
||||
}
|
||||
|
||||
BUILD_WAIT_FOR_BIT(ftgmac030_txdone, u32, ftgmac030_read_txdesc)
|
||||
|
||||
/*
|
||||
* Send a data block via Ethernet
|
||||
*/
|
||||
static int ftgmac030_send(struct eth_device *dev, void *packet, int length)
|
||||
{
|
||||
struct ftgmac030_data *priv = dev->priv;
|
||||
struct ftgmac030 *ftgmac030 = (struct ftgmac030 *)dev->iobase;
|
||||
struct ftgmac030_txdes *curr_des = &priv->txdes[priv->tx_index];
|
||||
ulong des_start = ((ulong)curr_des) & ~(ARCH_DMA_MINALIGN - 1);
|
||||
ulong des_end = des_start +
|
||||
roundup(sizeof(*curr_des), ARCH_DMA_MINALIGN);
|
||||
ulong data_start;
|
||||
ulong data_end;
|
||||
int rc;
|
||||
|
||||
invalidate_dcache_range(des_start, des_end);
|
||||
|
||||
if (curr_des->txdes0 & FTGMAC030_TXDES0_TXDMA_OWN) {
|
||||
debug("%s(): no TX descriptor available\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("%s(%x, %x)\n", __func__, (int)packet, length);
|
||||
|
||||
length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
|
||||
|
||||
/* initiate a transmit sequence */
|
||||
curr_des->txdes3 = (unsigned int)packet; /* TXBUF_BADR */
|
||||
|
||||
/* Flush data to be sent */
|
||||
data_start = curr_des->txdes3;
|
||||
data_end = data_start + roundup(length, ARCH_DMA_MINALIGN);
|
||||
flush_dcache_range(data_start, data_end);
|
||||
|
||||
/* only one descriptor on TXBUF */
|
||||
curr_des->txdes0 &= FTGMAC030_TXDES0_EDOTR;
|
||||
curr_des->txdes0 |= FTGMAC030_TXDES0_FTS |
|
||||
FTGMAC030_TXDES0_LTS |
|
||||
FTGMAC030_TXDES0_BUF_SIZE(length) |
|
||||
FTGMAC030_TXDES0_TXDMA_OWN;
|
||||
|
||||
/* Flush modified buffer descriptor */
|
||||
flush_dcache_range(des_start, des_end);
|
||||
|
||||
/* start transmit */
|
||||
writel(1, &ftgmac030->nptxpd);
|
||||
|
||||
/* wait for transfer to succeed */
|
||||
rc = wait_for_bit_ftgmac030_txdone(curr_des,
|
||||
FTGMAC030_TXDES0_TXDMA_OWN, false,
|
||||
FTGMAC030_TX_TIMEOUT_MS, true);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
debug("%s(): packet sent\n", __func__);
|
||||
|
||||
/* Move to next descriptor */
|
||||
priv->tx_index = (priv->tx_index + 1) % FTGMAC030_PKTBUFSTX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftgmac030_initialize(bd_t *bd)
|
||||
{
|
||||
struct eth_device *dev;
|
||||
struct ftgmac030_data *priv;
|
||||
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (!dev) {
|
||||
printf("%s(): failed to allocate dev\n", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Transmit and receive descriptors should align to 16 bytes */
|
||||
priv = (struct ftgmac030_data *)noncached_alloc(sizeof(struct ftgmac030_data),
|
||||
ARCH_DMA_MINALIGN);
|
||||
if (!priv) {
|
||||
printf("%s(): failed to allocate priv\n", __func__);
|
||||
goto free_dev;
|
||||
}
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
|
||||
sprintf(dev->name, "FTGMAC030");
|
||||
dev->iobase = GMAC_REG_BASE;
|
||||
dev->init = ftgmac030_init;
|
||||
dev->halt = ftgmac030_halt;
|
||||
dev->send = ftgmac030_send;
|
||||
dev->recv = ftgmac030_recv;
|
||||
dev->priv = priv;
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
return 1;
|
||||
|
||||
free_dev:
|
||||
free(dev);
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <phy.h>
|
||||
|
||||
#define MIIM_ICPLUS_PAGE_SELECT 0x14
|
||||
|
||||
static int icplus_phy_extread(struct phy_device *phydev, int addr,
|
||||
int devaddr, int regnum)
|
||||
{
|
||||
int oldpage = phy_read(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_ICPLUS_PAGE_SELECT);
|
||||
int val;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_ICPLUS_PAGE_SELECT, devaddr);
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, regnum);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_ICPLUS_PAGE_SELECT, oldpage);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int icplus_phy_extwrite(struct phy_device *phydev, int addr,
|
||||
int devaddr, int regnum, u16 val)
|
||||
{
|
||||
int oldpage = phy_read(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_ICPLUS_PAGE_SELECT);
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_ICPLUS_PAGE_SELECT, devaddr);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, regnum, val);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_ICPLUS_PAGE_SELECT, oldpage);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int icplus_config(struct phy_device *phydev)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
/* Digital IO Pin Driving Control Register */
|
||||
|
||||
/*RXC DRIVE*/
|
||||
reg = phydev->drv->readext(phydev, 0, 4, 22);
|
||||
reg &= ~(0x7 << 13);
|
||||
#ifdef CONFIG_LOTUS_FPGA
|
||||
reg |= (0x6 << 13);
|
||||
#else
|
||||
reg |= (0x4 << 13);
|
||||
#endif
|
||||
phydev->drv->writeext(phydev, 0, 4, 22, reg);
|
||||
|
||||
/*RXDx DRIVE*/
|
||||
reg = phydev->drv->readext(phydev, 0, 16, 26);
|
||||
reg &= ~(0x7FFF);
|
||||
#ifdef CONFIG_LOTUS_FPGA
|
||||
reg |= (0x6DB6);
|
||||
#else
|
||||
reg |= (0x36DB);
|
||||
#endif
|
||||
phydev->drv->writeext(phydev, 0, 16, 26, reg);
|
||||
|
||||
/*RXDx DRIVE*/
|
||||
reg = phydev->drv->readext(phydev, 0, 16, 27);
|
||||
reg &= ~(0x7FC7);
|
||||
#ifdef CONFIG_LOTUS_FPGA
|
||||
reg |= (0x6D86);
|
||||
#else
|
||||
reg |= (0x2484);
|
||||
#endif
|
||||
phydev->drv->writeext(phydev, 0, 16, 27, reg);
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int icplus_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return genphy_parse_link(phydev);
|
||||
}
|
||||
|
||||
/* Support for JL11x1 PHY */
|
||||
static struct phy_driver icplus_driver = {
|
||||
.name = "ICPlus IP101A/G",
|
||||
.uid = 0x02430c54,
|
||||
.mask = 0x0ffffff0,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &icplus_config,
|
||||
.startup = &icplus_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
.readext = &icplus_phy_extread,
|
||||
.writeext = &icplus_phy_extwrite,
|
||||
};
|
||||
|
||||
int phy_icplus_init(void)
|
||||
{
|
||||
phy_register(&icplus_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <phy.h>
|
||||
|
||||
#define MIIM_JL11X1_PAGE_SELECT 0x1f
|
||||
|
||||
static int jl11x1_phy_extread(struct phy_device *phydev, int addr,
|
||||
int devaddr, int regnum)
|
||||
{
|
||||
int oldpage = phy_read(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_JL11X1_PAGE_SELECT);
|
||||
int val;
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_JL11X1_PAGE_SELECT, devaddr);
|
||||
val = phy_read(phydev, MDIO_DEVAD_NONE, regnum);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_JL11X1_PAGE_SELECT, oldpage);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int jl11x1_phy_extwrite(struct phy_device *phydev, int addr,
|
||||
int devaddr, int regnum, u16 val)
|
||||
{
|
||||
int oldpage = phy_read(phydev, MDIO_DEVAD_NONE,
|
||||
MIIM_JL11X1_PAGE_SELECT);
|
||||
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_JL11X1_PAGE_SELECT, devaddr);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, regnum, val);
|
||||
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_JL11X1_PAGE_SELECT, oldpage);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jl11x1_config(struct phy_device *phydev)
|
||||
{
|
||||
/* Set green LED for Link, yellow LED for Active */
|
||||
phydev->drv->writeext(phydev, 0, 7, 19, 0x00);
|
||||
|
||||
genphy_config_aneg(phydev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jl11x1_startup(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = genphy_parse_link(phydev);
|
||||
|
||||
if (phydev->speed == SPEED_100) {
|
||||
unsigned int reg;
|
||||
|
||||
reg = phydev->drv->readext(phydev, 0, 24, 24);
|
||||
reg &= ~(0x7 << 10);
|
||||
reg |= (0x5 << 10);
|
||||
phydev->drv->writeext(phydev, 0, 24, 24, reg);
|
||||
// set page 7 reg 16 tx 3
|
||||
reg = phydev->drv->readext(phydev, 0, 7, 16);
|
||||
reg &= ~(0xf << 8);
|
||||
reg |= (0x3 << 8);
|
||||
phydev->drv->writeext(phydev, 0, 7, 16, reg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Support for JL11x1 PHY */
|
||||
static struct phy_driver JL11x1_driver = {
|
||||
.name = "JLSemi JL11x1",
|
||||
.uid = 0x937c4024,
|
||||
.mask = 0xffffffff,
|
||||
.features = PHY_BASIC_FEATURES,
|
||||
.config = &jl11x1_config,
|
||||
.startup = &jl11x1_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
.readext = &jl11x1_phy_extread,
|
||||
.writeext = &jl11x1_phy_extwrite,
|
||||
};
|
||||
|
||||
int phy_jlsemi_init(void)
|
||||
{
|
||||
phy_register(&JL11x1_driver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) LOTUS. All rights reserved.
|
||||
*/
|
||||
//#define DEBUG
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <wait_bit.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <cpu_func.h>
|
||||
#include <miiphy.h>
|
||||
#include <hexdump.h>
|
||||
|
||||
#include "ftgmac030.h"
|
||||
#include "marvell_phy.h"
|
||||
|
||||
static int m88e1116r_config_init(struct eth_device *dev, int phy_addr)
|
||||
{
|
||||
int temp;
|
||||
int err;
|
||||
|
||||
temp = ftgmac030_mdio_read(dev, phy_addr, MII_BMCR);
|
||||
temp |= BMCR_RESET;
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, MII_BMCR, temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mdelay(500);
|
||||
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, MII_MARVELL_PHY_PAGE, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
temp = ftgmac030_mdio_read(dev, phy_addr, MII_M1011_PHY_SCR);
|
||||
temp |= (7 << 12); /* max number of gigabit attempts */
|
||||
temp |= (1 << 11); /* enable downshift */
|
||||
temp |= MII_M1011_PHY_SCR_AUTO_CROSS;
|
||||
|
||||
debug("(%s) REG_PHY(%d) = 0x%x\n", __func__, MII_M1011_PHY_SCR, temp);
|
||||
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, MII_M1011_PHY_SCR, temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, MII_MARVELL_PHY_PAGE, 2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
temp = ftgmac030_mdio_read(dev, phy_addr, MII_M1116R_CONTROL_REG_MAC);
|
||||
temp &= ~(1 << 5);/*care is bit*/
|
||||
temp |= (1 << 4);
|
||||
|
||||
debug("(%s) REG_PHY(%d) = 0x%x\n", __func__, MII_M1116R_CONTROL_REG_MAC, temp);
|
||||
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, MII_M1116R_CONTROL_REG_MAC, temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, MII_MARVELL_PHY_PAGE, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
temp = ftgmac030_mdio_read(dev, phy_addr, MII_BMCR);
|
||||
temp |= BMCR_RESET;
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, MII_BMCR, temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
mdelay(500);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int marvell_phy_init(struct eth_device *dev, int phy_addr)
|
||||
{
|
||||
return m88e1116r_config_init(dev, phy_addr);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) LOTUS. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __MARVELL_PHY_H
|
||||
#define __MARVELL_PHY_H
|
||||
|
||||
#define PHY_MARVELL 0X141
|
||||
|
||||
#define MII_MARVELL_PHY_PAGE 22
|
||||
|
||||
#define MII_M1011_PHY_SCR 0x10
|
||||
#define MII_M1011_PHY_SCR_MDI 0x0000
|
||||
#define MII_M1011_PHY_SCR_MDI_X 0x0020
|
||||
#define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060
|
||||
|
||||
#define MII_M1116R_CONTROL_REG_MAC 21
|
||||
|
||||
int marvell_phy_init(struct eth_device *dev, int phy_addr);
|
||||
|
||||
#endif /* __MARVELL_PHY_H */
|
||||
@@ -0,0 +1,96 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
//#define DEBUG
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <net.h>
|
||||
#include <wait_bit.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <cpu_func.h>
|
||||
#include <miiphy.h>
|
||||
#include <hexdump.h>
|
||||
|
||||
#include "ftgmac030.h"
|
||||
#include "realtek_phy.h"
|
||||
|
||||
static int rtl821x_write_page(struct eth_device *dev, int phy_addr, int page)
|
||||
{
|
||||
return ftgmac030_mdio_write(dev, phy_addr, RTL821x_PAGE_SELECT, page);
|
||||
}
|
||||
|
||||
static int rtl8211f_config_init(struct eth_device *dev, int phy_addr)
|
||||
{
|
||||
int temp;
|
||||
int err;
|
||||
|
||||
/* change page to 0xa43 */
|
||||
err = rtl821x_write_page(dev, phy_addr, 0xa43);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* config page 0xa43 offset 0x18 */
|
||||
temp = ftgmac030_mdio_read(dev, phy_addr, RTL8211F_PHYCR1);
|
||||
temp |= RTL8211F_ALDPS_ENABLE | RTL8211F_ALDPS_PLL_OFF | RTL8211F_ALDPS_XTAL_OFF;
|
||||
|
||||
debug("(%s) REG_PHY(%d) = 0x%x\n", __func__, RTL8211F_PHYCR1, temp);
|
||||
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, RTL8211F_PHYCR1, temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* change page to 0xd08 */
|
||||
err = rtl821x_write_page(dev, phy_addr, 0xd08);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* config page 0xd08 offset 0x11 */
|
||||
temp = ftgmac030_mdio_read(dev, phy_addr, 0x11);
|
||||
|
||||
temp |= RTL8211F_TX_DELAY;
|
||||
debug("(%s) REG_PHY(%d) = 0x%x\n", __func__, 0x11, temp);
|
||||
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, 0x11, temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* config page 0xd08 offset 0x15 */
|
||||
temp = ftgmac030_mdio_read(dev, phy_addr, 0x15);
|
||||
|
||||
temp |= RTL8211F_RX_DELAY;
|
||||
debug("(%s) REG_PHY(%d) = 0x%x\n", __func__, 0x15, temp);
|
||||
|
||||
err = ftgmac030_mdio_write(dev, phy_addr, 0x15, temp);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* change page to 0x0 */
|
||||
err = rtl821x_write_page(dev, phy_addr, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int realtek_phy_init(struct eth_device *dev, int phy_addr)
|
||||
{
|
||||
int err = 0;
|
||||
u16 phy_id;
|
||||
|
||||
phy_id = ftgmac030_mdio_read(dev, phy_addr, MII_PHYSID2);
|
||||
|
||||
debug("(%s) REG_PHY(%d) = 0x%x\n", __func__, MII_PHYSID2, phy_id);
|
||||
|
||||
switch (phy_id) {
|
||||
case PHY_RTL8211F:
|
||||
err = rtl8211f_config_init(dev, phy_addr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef __REALTEK_PHY_H
|
||||
#define __REALTEK_PHY_H
|
||||
|
||||
#define PHY_REALTEK 0X1c
|
||||
|
||||
#define PHY_RTL8211F 0Xc916
|
||||
|
||||
#define RTL821x_PAGE_SELECT 0x1f
|
||||
|
||||
#define RTL8211F_PHYCR1 0x18
|
||||
|
||||
#define RTL8211F_MDI_MODE BIT(8)
|
||||
#define RTL8211F_MDI_MODE_EN BIT(9)
|
||||
|
||||
#define RTL8211F_TX_DELAY BIT(8)
|
||||
#define RTL8211F_RX_DELAY BIT(3)
|
||||
|
||||
#define RTL8211F_ALDPS_PLL_OFF BIT(1)
|
||||
#define RTL8211F_ALDPS_ENABLE BIT(2)
|
||||
#define RTL8211F_ALDPS_XTAL_OFF BIT(12)
|
||||
|
||||
int realtek_phy_init(struct eth_device *dev, int phy_addr);
|
||||
|
||||
#endif /* __REALTEK_PHY_H */
|
||||
@@ -0,0 +1,174 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <config.h>
|
||||
#include "bspeth.h"
|
||||
#include "sys.h"
|
||||
#include "ftgmac030.h"
|
||||
|
||||
static void bspeth_reset(int rst)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = _readl(BSPETH_MAC_CRG_REG);
|
||||
if (rst)
|
||||
val |= ETH_SOFT_RESET;
|
||||
else
|
||||
val &= ~ETH_SOFT_RESET;
|
||||
|
||||
_writel(val, BSPETH_MAC_CRG_REG);
|
||||
|
||||
udelay(100); /* delay 100us */
|
||||
|
||||
}
|
||||
|
||||
static inline void bspeth_clk_ena(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static inline void bspeth_clk_dis(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void bspeth_reset_internal_phy(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void bspeth_reset_external_phy_by_crg(void)
|
||||
{
|
||||
u32 v;
|
||||
u32 phy_reset_n;
|
||||
|
||||
/* bit[1]*/
|
||||
phy_reset_n = readl(BSPETH_CFG_CRG_REG);
|
||||
phy_reset_n &= ETH_PHY_RST_N;
|
||||
|
||||
/************************************************/
|
||||
/* reset external phy with default reset pin */
|
||||
v = readl(BSPETH_PHY_CRG_REG);
|
||||
|
||||
if (phy_reset_n)
|
||||
v |= ETH_EXTERNAL_PHY_RESET;
|
||||
else
|
||||
v &= ~ETH_EXTERNAL_PHY_RESET;
|
||||
|
||||
writel(v, BSPETH_PHY_CRG_REG);
|
||||
mdelay(10); /* delay 10ms */
|
||||
|
||||
/* then, cancel reset, and should delay some time */
|
||||
v = readl(BSPETH_PHY_CRG_REG);
|
||||
|
||||
if (phy_reset_n)
|
||||
v &= ~ETH_EXTERNAL_PHY_RESET;
|
||||
else
|
||||
v |= ETH_EXTERNAL_PHY_RESET;
|
||||
|
||||
writel(v, BSPETH_PHY_CRG_REG);
|
||||
|
||||
mdelay(20); /* delay 20ms */
|
||||
|
||||
/* then, cancel reset, and should delay some time */
|
||||
v = readl(BSPETH_PHY_CRG_REG);
|
||||
|
||||
if (phy_reset_n)
|
||||
v |= ETH_EXTERNAL_PHY_RESET;
|
||||
else
|
||||
v &= ~ETH_EXTERNAL_PHY_RESET;
|
||||
|
||||
writel(v, BSPETH_PHY_CRG_REG);
|
||||
|
||||
mdelay(150); /* delay 150ms */
|
||||
|
||||
}
|
||||
|
||||
static void bspeth_reset_external_phy_by_gpio(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void bspeth_phy_reset(void)
|
||||
{
|
||||
bspeth_reset_internal_phy();
|
||||
bspeth_reset_external_phy_by_crg();
|
||||
bspeth_reset_external_phy_by_gpio();
|
||||
}
|
||||
|
||||
static void bspeth_funsel_config(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void bspeth_funsel_restore(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
///**************************************************/
|
||||
//void bspeth_sys_startup(void)
|
||||
//{
|
||||
// bspeth_clk_ena();
|
||||
// /* undo reset */
|
||||
// bspeth_reset(0);
|
||||
//}
|
||||
|
||||
void bspeth_sys_allstop(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
u32 bspeth_get_phy_intf(void)
|
||||
{
|
||||
u32 phy_intf;
|
||||
|
||||
/* bit[0]: 0 -- rmii,1 -- rgmii bit[3]:1 --mii or gmii*/
|
||||
phy_intf = readl(BSPETH_CFG_CRG_REG);
|
||||
phy_intf &= ETH_PHY_INTF;
|
||||
|
||||
if (phy_intf & bit(3))
|
||||
return FTGMAC030_MODE_MII_GMII;
|
||||
else if (phy_intf & bit(0))
|
||||
return FTGMAC030_MODE_RGMII;
|
||||
else
|
||||
return FTGMAC030_MODE_RMII;
|
||||
}
|
||||
|
||||
/* Set rgmii tx delay for 2ns */
|
||||
void bspeth_set_tx_delay(void)
|
||||
{
|
||||
u32 regval;
|
||||
u32 timeout = 100;//1ms
|
||||
|
||||
regval = readl(BSPETH_DLY_CRG_REG);
|
||||
|
||||
if(!(regval & ETH_DLY_SEL)) {
|
||||
writel(regval | ETH_DLY_SEL, BSPETH_DLY_CRG_REG);
|
||||
|
||||
do {
|
||||
udelay(10);
|
||||
regval = readl(BSPETH_DLY_STAT_REG);
|
||||
--timeout;
|
||||
} while ((!(regval & ETH_DLY_STAT) && timeout));
|
||||
}
|
||||
|
||||
if(!timeout)
|
||||
printf("Error: bspeth_set_tx_delay timeout!\n");
|
||||
}
|
||||
|
||||
void bspeth_sys_init(void)
|
||||
{
|
||||
bspeth_funsel_config();
|
||||
bspeth_sys_allstop();
|
||||
bspeth_clk_ena();
|
||||
bspeth_reset(1);
|
||||
bspeth_reset(0);
|
||||
bspeth_phy_reset();
|
||||
}
|
||||
|
||||
void bspeth_sys_exit(void)
|
||||
{
|
||||
bspeth_funsel_restore();
|
||||
bspeth_sys_allstop();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#ifndef __BSPETH_SYS_H__
|
||||
#define __BSPETH_SYS_H__
|
||||
|
||||
void bspeth_sys_init(void);
|
||||
void bspeth_sys_exit(void);
|
||||
|
||||
//void bspeth_sys_startup(void);
|
||||
//void bspeth_sys_allstop(void);
|
||||
|
||||
u32 bspeth_get_phy_intf(void);
|
||||
void bspeth_set_tx_delay(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user