GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -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 -- rmii1 -- 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