增加bootload程序

This commit is contained in:
2025-11-14 21:41:29 +08:00
parent daaf7aea06
commit 9c16ad5e3d
8378 changed files with 2997890 additions and 0 deletions

View File

@@ -0,0 +1,316 @@
/*
* dp83848.c
*
* Copyright (c) 2020 Semidrive Semiconductor.
* All rights reserved.
*
* Description: eth phy dp83848 drv
*
* Revision History:
* -----------------
*/
#include <stdlib.h>
#include "debug.h"
#include "CLI.h"
#include "phy.h"
#define MII_BMCR 0x00 /* Basic mode control register */
#define MII_BMSR 0x01 /* Basic mode status register */
#define MII_PHYSID1 0x02 /* PHYS ID 1 */
#define MII_PHYSID2 0x03 /* PHYS ID 2 */
#define MII_ADVERTISE 0x04 /* Advertisement control reg */
#define MII_LPA 0x05 /* Link partner ability reg */
#define MII_EXPANSION 0x06 /* Expansion register */
#define MII_PHYSTS 0x10
#define MII_PHYCR 0x19
/* Basic mode control register. */
#define BMCR_RESV 0x003f /* Unused... */
#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
#define BMCR_CTST 0x0080 /* Collision test */
#define BMCR_FULLDPLX 0x0100 /* Full duplex */
#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
#define BMCR_ISOLATE 0x0400 /* Isolate data paths from MII */
#define BMCR_PDOWN 0x0800 /* Enable low power state */
#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
#define BMCR_RESET 0x8000 /* Reset to default state */
#define BMCR_SPEED10 0x0000 /* Select 10Mbps */
/* Basic mode status register */
#define BMSR_LINK_STATUS 0x4
/* Advertisement control register. */
#define ADVERTISE_SLCT 0x001f /* Selector bits */
#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
#define ADVERTISE_RESV 0x1000 /* Unused... */
#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
/* PHY status register */
#define PHYSTS_DUPLEX 0x40
#define PHYSTS_SPEED 0x20
/* PHY control register */
#define PHYCR_MDIX_EN 0x8000
#define PHY_CLI_EN 1
#if PHY_CLI_EN
static phy_dev_t *g_dp83848_dev;
#endif
static int dp83848_read(phy_dev_t *dev, uint32_t regaddr)
{
phy_bus_t *bus = dev->bus;
int ret = bus->ops->mdio_read(bus, dev->phy_addr, 0xFF, regaddr);
if (ret < 0)
ssdk_printf(SSDK_ERR, "dp83848_read err!\n");
return ret;
}
static int dp83848_write(phy_dev_t *dev, uint32_t regaddr, uint16_t val)
{
phy_bus_t *bus = dev->bus;
if (bus->ops->mdio_write(bus, dev->phy_addr, 0xFF, regaddr, val)) {
ssdk_printf(SSDK_ERR, "dp83848_write err!\n");
return -1;
}
return 0;
}
static int dp83848_reset(phy_dev_t *dev)
{
int timeout = 500;
int reg_val;
if (dp83848_write(dev, MII_BMCR, BMCR_RESET)) {
ssdk_printf(SSDK_ERR, "PHY reset failed\n");
return -1;
}
while (timeout--) {
reg_val = dp83848_read(dev, MII_BMCR);
if (reg_val < 0) {
ssdk_printf(SSDK_ERR, "BMCR read failed\n");
return -2;
}
if (!(reg_val & BMCR_RESET))
break;
udelay(1000);
}
if (reg_val & BMCR_RESET) {
ssdk_printf(SSDK_ERR, "PHY reset timeout\n");
return -3;
}
return 0;
}
static uint32_t dp83848_get_phy_id(phy_dev_t *dev)
{
int reg_val;
reg_val = dp83848_read(dev, MII_PHYSID1);
if (reg_val < 0) {
ssdk_printf(SSDK_ERR, "Read phy id1 error\n");
return reg_val;
}
reg_val <<= 16;
int temp = dp83848_read(dev, MII_PHYSID2);
if (temp < 0) {
ssdk_printf(SSDK_ERR, "Read phy id2 error\n");
return temp;
}
reg_val |= temp;
return reg_val;
}
static int dp83848_config_aneg(phy_dev_t *dev)
{
int reg_val, ret, timeout = 1000;
if (dev->auto_negotiation) {
reg_val = dp83848_read(dev, MII_ADVERTISE);
if (reg_val < 0) {
ssdk_printf(SSDK_ERR, "Read advertise error\n");
return reg_val;
}
reg_val |= ADVERTISE_100FULL | ADVERTISE_100HALF |
ADVERTISE_10FULL | ADVERTISE_10HALF;
ret = dp83848_write(dev, MII_ADVERTISE, reg_val);
if (ret) {
ssdk_printf(SSDK_ERR, "Config advertisement register failed\n");
return ret;
}
reg_val = dp83848_read(dev, MII_BMCR);
if (reg_val < 0) {
ssdk_printf(SSDK_ERR, "Read BMCR failed\n");
return reg_val;
}
reg_val |= BMCR_ANENABLE;
ret = dp83848_write(dev, MII_BMCR, reg_val);
if (ret)
ssdk_printf(SSDK_ERR, "Write BMCR failed\n");
}
else {
reg_val = dp83848_read(dev, MII_BMCR);
if (reg_val < 0) {
ssdk_printf(SSDK_ERR, "Read BMCR failed\n");
return reg_val;
}
reg_val &= ~BMCR_ANENABLE;
if (dev->speed == PHY_SPEED_10)
reg_val &= ~BMCR_SPEED100;
else
reg_val |= BMCR_SPEED100;
if (dev->duplex_mode == ETH_PHY_DUPLEX_MODE_HALF)
reg_val &= ~BMCR_FULLDPLX;
else
reg_val |= BMCR_FULLDPLX;
ret = dp83848_write(dev, MII_BMCR, reg_val);
if (ret)
ssdk_printf(SSDK_ERR, "Write BMCR failed\n");
}
if (ret)
return ret;
if (dev->auto_negotiation) {
ssdk_printf(SSDK_EMERG, "Wait for dp83848 link ...\n");
while (timeout--) {
reg_val = dp83848_read(dev, MII_BMSR);
if ((reg_val >= 0) && (reg_val & BMSR_LINK_STATUS))
break;
udelay(1);
}
if ((reg_val < 0) || !(reg_val & BMSR_LINK_STATUS)) {
ssdk_printf(SSDK_EMERG, "Link failed\n");
return -1;
}
else
ssdk_printf(SSDK_EMERG, "Link successfully\n");
}
return 0;
}
static int dp83848_startup(phy_dev_t *dev)
{
int reg_val, ret;
reg_val = dp83848_read(dev, MII_PHYSTS);
if (reg_val < 0) {
ssdk_printf(SSDK_ERR, "Read PHYSTS failed\n");
return reg_val;
}
ssdk_printf(SSDK_INFO, "PHYSTS value 0x%x\n", reg_val);
if (reg_val & PHYSTS_SPEED)
dev->speed = PHY_SPEED_10;
else
dev->speed = PHY_SPEED_100;
if (reg_val & PHYSTS_DUPLEX)
dev->duplex_mode = ETH_PHY_DUPLEX_MODE_FULL;
else
dev->duplex_mode = ETH_PHY_DUPLEX_MODE_HALF;
reg_val = dp83848_read(dev, MII_BMCR);
if (reg_val < 0) {
ssdk_printf(SSDK_ERR, "Read BMCR failed\n");
return reg_val;
}
reg_val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
ret = dp83848_write(dev, MII_BMCR, reg_val);
if (ret) {
ssdk_printf(SSDK_ERR, "Config BMCR failed\n");
goto out;
}
ret = dp83848_write(dev, MII_PHYCR, PHYCR_MDIX_EN | dev->phy_addr);
if (ret) {
ssdk_printf(SSDK_ERR, "Config PHYCR failed\n");
goto out;
}
ssdk_printf(SSDK_INFO, "PHY status 0x%x\n", dp83848_read(dev, MII_BMSR));
out:
return ret;
}
int dp83848_init(phy_dev_t *dev)
{
#if PHY_CLI_EN
g_dp83848_dev = dev;
#endif
if (dp83848_reset(dev))
return -1;
ssdk_printf(SSDK_INFO, "PHY ID 0x%x\n",
dp83848_get_phy_id(dev));
if (dp83848_config_aneg(dev))
return -2;
return dp83848_startup(dev);
}
#if PHY_CLI_EN
static int phy_dump(int argc, char *argv[])
{
if (!g_dp83848_dev) {
printf("dp83848 is not availiable\n");
return 0;
}
if (argc == 0) {
printf("phy <reg_num> [val]\n");
return 0;
}
int reg_num = strtoul(argv[0], NULL, 0);
if (argc == 1)
printf("read reg %d: 0x%x\n", reg_num, dp83848_read(g_dp83848_dev, reg_num));
else {
int val = strtoul(argv[1], NULL, 0);
printf("write reg %d val 0x%x result %d\n", reg_num, val,
dp83848_write(g_dp83848_dev, reg_num, val));
}
return 0;
}
CLI_CMD("phy", "\r\nphy:\r\n phy reg dump\r\n", phy_dump);
#endif

View File

@@ -0,0 +1,35 @@
/**
* phy.c
*
* Copyright (c) 2020 Semidrive Semiconductor.
* All rights reserved.
*
* Description: eth phy driver
*
* Revision History:
* -----------------
*/
#include "armv7-r/irq.h"
#include "phy.h"
void phy_dev_register(phy_bus_t *bus, phy_dev_t *dev)
{
irq_state_t state;
state = arch_irq_save();
list_add_tail(&bus->phy_dev_list, &dev->node);
bus->ref_cnt++;
dev->bus = bus;
arch_irq_restore(state);
}
void phy_init(phy_bus_t *bus)
{
phy_dev_t *phy;
list_for_every_entry(&bus->phy_dev_list, phy, phy_dev_t, node) {
if (phy->init)
phy->init(phy);
}
}

View File

@@ -0,0 +1,75 @@
/**
* phy.h
*
* Copyright (c) 2020 Semidrive Semiconductor.
* All rights reserved.
*
* Description: eth phy driver header file
*
* Revision History:
* -----------------
*/
#ifndef _PHY_H_
#define _PHY_H_
#include <stdint.h>
#include "lib/list.h"
#include "../sdrv_mac_lld.h"
typedef enum {
/* Automatic Negotiation */
ETH_PHY_CONN_NEG_AUTO = 0,
/* Master */
ETH_PHY_CONN_NEG_MASTER,
/* Slave */
ETH_PHY_CONN_NEG_SLAVE
} eth_phy_conn_neg_mode_type;
typedef enum {
/* Half duplex Ethernet connection */
ETH_PHY_DUPLEX_MODE_HALF = 0,
/* 0x01 Full duplex Ethernet connection */
ETH_PHY_DUPLEX_MODE_FULL
} eth_duplex_mode_type;
typedef enum phy_speed{
PHY_SPEED_10 = 0x0,
PHY_SPEED_100,
PHY_SPEED_1000,
} phy_speed_t;
typedef struct phy_bus phy_bus_t;
typedef struct phy_bus_ops {
int (*mdio_read)(phy_bus_t *bus, uint32_t phyaddr, uint32_t devaddr,
uint32_t regaddr);
int (*mdio_write)(phy_bus_t *bus , uint32_t phyaddr, uint32_t devaddr,
uint32_t regaddr, uint32_t data);
} phy_bus_ops_t;
struct phy_bus {
phy_bus_ops_t *ops;
uint32_t ref_cnt;
struct list_node phy_dev_list;
};
typedef struct phy_dev phy_dev_t;
struct phy_dev {
struct list_node node;
phy_bus_t *bus;
uint32_t phy_addr;
eth_phy_conn_neg_mode_type conn_neg_mode;
eth_duplex_mode_type duplex_mode;
phy_speed_t speed;
bool auto_negotiation;
int (*init)(phy_dev_t *dev);
};
void phy_dev_register(phy_bus_t *bus, phy_dev_t *dev);
void phy_init(phy_bus_t *bus);
#endif

View File

@@ -0,0 +1,326 @@
/*
* rtl9010.c
*
* Copyright (c) 2020 Semidrive Semiconductor.
* All rights reserved.
*
* Description: eth phy rtl9010 drv
*
* Revision History:
* -----------------
*/
#include <stdlib.h>
#include "debug.h"
#include "CLI.h"
#include "phy.h"
#define LINK_UP 0
#define LINK_DOWN -100
#define PHY_CLI_EN 1
#if PHY_CLI_EN
static phy_dev_t *g_rtl9010_dev;
#endif
static int rtl9010_read(phy_dev_t *dev, uint32_t regaddr)
{
phy_bus_t *bus = dev->bus;
int ret = bus->ops->mdio_read(bus, dev->phy_addr, 0xFF, regaddr);
if (ret < 0)
ssdk_printf(SSDK_ERR, "rtl9010_read err!\n");
return ret;
}
static int rtl9010_write(phy_dev_t *dev, uint32_t regaddr, uint16_t val)
{
phy_bus_t *bus = dev->bus;
if (bus->ops->mdio_write(bus, dev->phy_addr, 0xFF, regaddr, val)) {
ssdk_printf(SSDK_ERR, "rtl9010_write err!\n");
return -1;
}
return 0;
}
static int rtl9010_initial_config(phy_dev_t *dev)
{
int mdio_data = 0;
int timer = 2000; // set a 2ms timer
// PHY Parameter Start //
rtl9010_write(dev, 31, 0x0BC4);
rtl9010_write(dev, 21, 0x16FE);
rtl9010_write(dev, 27, 0xB820);
rtl9010_write(dev, 28, 0x0010);
rtl9010_write(dev, 27, 0xB830);
rtl9010_write(dev, 28, 0x8000);
rtl9010_write(dev, 27, 0xB800);
mdio_data = (rtl9010_read(dev, 28) & 0x0040);
while (mdio_data != 0x0040) {
rtl9010_write(dev, 27, 0xB800);
mdio_data = (rtl9010_read(dev, 28) & 0x0040);
timer--;
if (timer == 0) {
return -1;
}
}
rtl9010_write(dev, 27, 0x8020);
rtl9010_write(dev, 28, 0x9100);
rtl9010_write(dev, 27, 0xB82E);
rtl9010_write(dev, 28, 0x0001);
rtl9010_write(dev, 27, 0xB820);
rtl9010_write(dev, 28, 0x0290);
rtl9010_write(dev, 27, 0xA012);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0xA014);
rtl9010_write(dev, 28, 0xD700);
rtl9010_write(dev, 28, 0x880F);
rtl9010_write(dev, 28, 0x262D);
rtl9010_write(dev, 27, 0xA01A);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0xA000);
rtl9010_write(dev, 28, 0x162C);
rtl9010_write(dev, 27, 0xB820);
rtl9010_write(dev, 28, 0x0210);
rtl9010_write(dev, 27, 0xB82E);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0x8020);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0xB820);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0xB800);
mdio_data = rtl9010_read(dev, 28) & 0x0040;
timer = 2000; // set a 2ms timer
while (mdio_data != 0x0000) {
rtl9010_write(dev, 27, 0xB800);
mdio_data = (rtl9010_read(dev, 28) & 0x0040);
timer--;
if (timer == 0) {
return -2;
}
}
// End //
/* Set rx delay to 2ns. */
rtl9010_write(dev, 27, 0xD04A);
rtl9010_write(dev, 28, 7);
/* Set tx delay to 2ns. */
rtl9010_write(dev, 27, 0xD084);
rtl9010_write(dev, 28, 0x4007);
rtl9010_write(dev, 0, 0x8000); // PHY soft-reset
mdio_data = 0;
while (mdio_data != 0x0140) { // Check soft-reset complete
mdio_data = rtl9010_read(dev, 0);
}
return 0;
}
static int rtl9010_initial_with_nway_config(phy_dev_t *dev)
{
int mdio_data = 0;
int timer = 2000; // set a 2ms timer
// PHY Parameter Start //
rtl9010_write(dev, 31,0x0A54);
rtl9010_write(dev, 21,0xFA06);
rtl9010_write(dev, 31,0x0BC4);
rtl9010_write(dev, 21,0x16FE);
rtl9010_write(dev, 27, 0xB820);
rtl9010_write(dev, 28, 0x0010);
rtl9010_write(dev, 27, 0xB830);
rtl9010_write(dev, 28, 0x8000);
rtl9010_write(dev, 27, 0xB800);
mdio_data = (rtl9010_read(dev, 28) & 0x0040);
while (mdio_data != 0x0040) {
rtl9010_write(dev, 27, 0xB800);
mdio_data = (rtl9010_read(dev, 28) & 0x0040);
timer--;
if (timer == 0) {
return -1;
}
}
rtl9010_write(dev, 27, 0x8020);
rtl9010_write(dev, 28, 0x9100);
rtl9010_write(dev, 27, 0xB82E);
rtl9010_write(dev, 28, 0x0001);
rtl9010_write(dev, 27, 0xB820);
rtl9010_write(dev, 28, 0x0290);
rtl9010_write(dev, 27, 0xA012);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0xA014);
rtl9010_write(dev, 28, 0x2C03);
rtl9010_write(dev, 28, 0x2C07);
rtl9010_write(dev, 28, 0x2C0B);
rtl9010_write(dev, 28, 0x6054);
rtl9010_write(dev, 28, 0xA701);
rtl9010_write(dev, 28, 0xD500);
rtl9010_write(dev, 28, 0x2108);
rtl9010_write(dev, 28, 0x4054);
rtl9010_write(dev, 28, 0x8701);
rtl9010_write(dev, 28, 0xA74A);
rtl9010_write(dev, 28, 0x20DE);
rtl9010_write(dev, 28, 0xD700);
rtl9010_write(dev, 28, 0x880F);
rtl9010_write(dev, 28, 0x262D);
rtl9010_write(dev, 27, 0xA01A);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0xA004);
rtl9010_write(dev, 28, 0x062C);
rtl9010_write(dev, 27, 0xA002);
rtl9010_write(dev, 28, 0x00DD);
rtl9010_write(dev, 27, 0xA000);
rtl9010_write(dev, 28, 0x7107);
rtl9010_write(dev, 27, 0xB820);
rtl9010_write(dev, 28, 0x0210);
rtl9010_write(dev, 27, 0xB82E);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0x8020);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0xB820);
rtl9010_write(dev, 28, 0x0000);
rtl9010_write(dev, 27, 0xB800);
mdio_data = (rtl9010_read(dev, 28) & 0x0040);
timer = 2000; // set a 2ms timer
while (mdio_data != 0x0000) {
rtl9010_write(dev, 27, 0xB800);
mdio_data = (rtl9010_read(dev, 28) & 0x0040);
timer--;
if (timer == 0) {
return -2;
}
}
// End //
/* Set rx delay to 2ns. */
rtl9010_write(dev, 27, 0xD04A);
rtl9010_write(dev, 28, 7);
/* Set tx delay to 2ns. */
rtl9010_write(dev, 27, 0xD084);
rtl9010_write(dev, 28, 0x4007);
rtl9010_write(dev, 0, 0x8000); // PHY soft-reset
mdio_data = 0;
while (mdio_data != 0x0140) { // Check soft-reset complete
mdio_data = rtl9010_read(dev, 0);
}
return 0;
}
static int rtl9010_get_link_status(phy_dev_t *dev)
{
int mdio_data = 0;
int locok = 0;
int remok = 0;
int link_status = 0;
int pcs_status;
int pcs_status_checkOK=0;
mdio_data = rtl9010_read(dev, 1);
mdio_data = rtl9010_read(dev, 1);//Read twice for current link status.
link_status = (mdio_data & 0x0004);
rtl9010_write(dev, 31, 0x0A60);
mdio_data = rtl9010_read(dev, 16);
pcs_status = (mdio_data & 0x00FF);
if (dev->speed == PHY_SPEED_1000){
mdio_data = rtl9010_read(dev, 10);
locok = ((mdio_data & 0x2000) == 0x2000);
remok = ((mdio_data & 0x1000) == 0x1000);
if (pcs_status == 0x0037)
pcs_status_checkOK = 1;
}
else {
rtl9010_write(dev, 31, 0x0A64);
mdio_data = rtl9010_read(dev, 23);
locok = ((mdio_data & 0x0004) == 0x0004);
remok = ((mdio_data & 0x0400) == 0x0400);
if (pcs_status == 0x0044)
pcs_status_checkOK = 1;
}
ssdk_printf(SSDK_INFO, "link_status = 0x%04X\r\n",link_status);
ssdk_printf(SSDK_INFO, "locok = 0x%04X\r\n",locok);
ssdk_printf(SSDK_INFO, "remok = 0x%04X\r\n",remok);
ssdk_printf(SSDK_INFO, "pcs_status = 0x%04X\r\n",pcs_status);
if ((link_status == 0x0004) & (locok) & (remok) &
pcs_status_checkOK)
return LINK_UP;
else
return LINK_DOWN;
}
int rtl9010_init(phy_dev_t *dev)
{
int ret = 0, timeout = 1000;
#if PHY_CLI_EN
g_rtl9010_dev = dev;
#endif
if (dev->auto_negotiation)
ret = rtl9010_initial_with_nway_config(dev);
else
ret = rtl9010_initial_config(dev);
if (!ret && dev->auto_negotiation) {
ssdk_printf(SSDK_EMERG, "Wait for rtl9010 link ...\n");
while (timeout--) {
ret = rtl9010_get_link_status(dev);
if (ret == LINK_UP) {
ssdk_printf(SSDK_EMERG, "Link successfully\n");
return ret;
}
}
ssdk_printf(SSDK_EMERG, "Link failed\n");
}
return ret;
}
#if PHY_CLI_EN
static int rtl9010_dump(int argc, char *argv[])
{
if (!g_rtl9010_dev) {
printf("rtl9010 is not availiable\n");
return 0;
}
if (argc == 0) {
printf("phy <reg_num> [val]\n");
return 0;
}
int reg_num = strtoul(argv[0], NULL, 0);
if (argc == 1)
printf("read reg %d: 0x%x\n", reg_num, rtl9010_read(g_rtl9010_dev, reg_num));
else {
int val = strtoul(argv[1], NULL, 0);
printf("write reg %d val 0x%x result %d\n", reg_num, val,
rtl9010_write(g_rtl9010_dev, reg_num, val));
}
return 0;
}
CLI_CMD("rtl", "\r\nrtl:\r\n rtl reg dump\r\n", rtl9010_dump);
#endif

View File

@@ -0,0 +1,786 @@
/**
* dwc_eth.c
*
* Copyright (c) 2021 Semidrive Semiconductor.
* All rights reserved.
*
* Description: dw eth mac drv
*
* Revision History:
* -----------------
*/
#include <stdlib.h>
#include <string.h>
#include "debug.h"
#include "param.h"
#include "armv7-r/barriers.h"
#include "armv7-r/cache.h"
#include "irq_num.h"
#include "irq.h"
#include "sdrv_mac_lld.h"
#include "sdrv_eth.h"
#include "phy/phy.h"
#include <wdt_refresh.h>
/* Eth frame header and crc length. */
#define ETH_FRAME_HEADER_LEN (6 + 6 + 2)
#define ETH_FRAME_OVERHEAD_LEN (ETH_FRAME_HEADER_LEN + 4)
#if !CONFIG_ETH_USE_HEAP
#define MAX_ETH_CNT 2
#ifndef CONFIG_ARCH_CACHE_LINE
#define CONFIG_ARCH_CACHE_LINE 32
#endif
typedef struct {
struct eqos_desc desc;
} __ALIGNED(EQOS_DESCRIPTOR_ALIGN) eqos_desc_t;
struct eqos_data {
bool used;
dwc_eth_dev_t dev;
struct eqos_priv eqos;
eqos_desc_t descs[EQOS_DESCRIPTORS_NUM];
uint8_t rx_dma_buf[EQOS_RX_BUFFER_SIZE] __ALIGNED(CONFIG_ARCH_CACHE_LINE);
uint8_t tx_dma_buf[EQOS_TX_BUFFER_SIZE] __ALIGNED(CONFIG_ARCH_CACHE_LINE);
};
static struct eqos_data g_eqos_data[MAX_ETH_CNT];
#endif
static void *eqos_alloc_descs(struct eqos_priv *eqos, unsigned int num)
{
/* Align dma descriptors base address & size to cache line to avoid
* descriptors corrupted by cacahe line invalidation needed by other
* address, if descriptors has not been wrote to ram.
*/
eqos->desc_size = ALIGN(sizeof(struct eqos_desc),
(unsigned int)EQOS_DESCRIPTOR_ALIGN);
#if !CONFIG_ETH_USE_HEAP
return containerof(eqos, struct eqos_data, eqos)->descs;
#else
#if __GNUC__
return (void *)memalign(eqos->desc_size, num * eqos->desc_size);
#else
return aligned_alloc(eqos->desc_size, num * eqos->desc_size);
#endif
#endif
}
#if CONFIG_ETH_USE_HEAP
static void eqos_free_descs(void *descs)
{
free(descs);
}
#endif
static struct eqos_desc *eqos_get_desc(struct eqos_priv *eqos, unsigned int num,
bool rx)
{
void *desc = (uint8_t *)eqos->descs +
((rx ? EQOS_DESCRIPTORS_TX : 0) + num) * eqos->desc_size;
return desc;
}
/**
* @brief Init the Controller DMA Block
*/
static inline void mac_init_dma(uint32_t regbase, struct eqos_priv *eqos)
{
uint8_t ch_cnt = 0U;
dwmac_dma_bus_init(regbase, DMA_AXI_MAX_OSR_LIMIT | DMA_SYS_BUS_AAL |
DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | DMA_AXI_BLEN4);
for (ch_cnt = 0; ch_cnt < ETH_MAX_DMA_CHANNEL; ch_cnt++) {
// DMA Control
dwmac_dma_init_channel(regbase, 0, ch_cnt, eqos->dsl);
// rx ring length
dwmac_set_rx_ring_len(regbase, EQOS_DESCRIPTORS_RX - 1, ch_cnt);
// init_rx_chan
dwmac_dma_init_rx_chan(regbase, (paddr_t)eqos_get_desc(eqos, 0, true),
EQOS_MAX_PACKET_SIZE, ch_cnt);
// rx bufsize
dwmac_set_bfsize(regbase, 2048, ch_cnt);//2048 20250112<31>޸<EFBFBD>Ϊ 4096
// tx ring length
dwmac_set_tx_ring_len(regbase, EQOS_DESCRIPTORS_TX - 1, ch_cnt);
// init_tx_chan
dwmac_dma_init_tx_chan(regbase, (paddr_t)eqos_get_desc(eqos, 0, false),
ch_cnt);
// set tx tail ptr to next address after the last tx descriptor, so that
// dma will never suspend.
dwmac_set_tx_tail_ptr(regbase, (uint32_t)eqos_get_desc(eqos, EQOS_DESCRIPTORS_TX, false),
ch_cnt);
// set rx tail ptr to next address after the last tx descriptor, so that
// dma will never suspend.
dwmac_set_rx_tail_ptr(regbase,
(paddr_t)eqos_get_desc(eqos, EQOS_DESCRIPTORS_RX, true),
ch_cnt);
dwmac_enable_dma_irq(regbase, ch_cnt, false, false);
}
}
/**
* @brief Init the Controller MTL Block
*/
static inline void mac_init_mtl(uint32_t regbase)
{
uint8_t ch_cnt = 0U;
dwmac_prog_mtl_rx_algorithms(regbase, MTL_RX_ALGORITHM_SP);
dwmac_prog_mtl_tx_algorithms(regbase, MTL_OPERATION_SCHALG_WRR);
for (ch_cnt = 0; ch_cnt < ETH_MAX_DMA_CHANNEL; ch_cnt++) {
// rx mtl map with dma
dwmac_map_mtl_dma(regbase, ch_cnt, ch_cnt);
dwmac_rx_queue_enable(regbase, MTL_QUEUE_MODE_DCB, ch_cnt);
dwmac_dma_tx_chan_op_mode(regbase, ch_cnt, SF_MODE, 10240, MTL_QUEUE_MODE_DCB);
dwmac_dma_rx_chan_op_mode(regbase, ch_cnt, SF_MODE, 10240, MTL_QUEUE_MODE_DCB);
}
}
static inline void mac_start(uint32_t regbase, bool start)
{
uint8_t ch_cnt = 0U;
for (ch_cnt = 0; ch_cnt < ETH_MAX_DMA_CHANNEL; ch_cnt++) {
if (start) {
// start rx
dwmac_dma_start_rx(regbase, ch_cnt);
// start tx
dwmac_dma_start_tx(regbase, ch_cnt);
}
else {
// stop rx
dwmac_dma_stop_rx(regbase, ch_cnt);
// stop tx
dwmac_dma_stop_tx(regbase, ch_cnt);
}
}
}
static void eth_mac_init(dwc_eth_config_t *cfg, struct eqos_priv *eqos)
{
//DMA core sw reset
dwmac_dma_reset(cfg->base);
uint32_t skip_len = eqos->desc_size - sizeof(struct eqos_desc);
uint8_t bus_width = cfg->dma_bus_width ? cfg->dma_bus_width : 64;
eqos->dsl = skip_len * 8 / bus_width;
//DMA init
mac_init_dma(cfg->base, eqos);
//MTL init
mac_init_mtl(cfg->base);
//core init
phy_speed_t speed = (cfg->phy[0].phy_addr == ~0) ?
PHY_SPEED_1000 : cfg->phy[0].speed;
dwmac_core_init(cfg->base, cfg->mtu, speed, cfg->mac_addr);
dwmac_mac_rx_queue_mcbc_routing(cfg->base, 0);
}
static inline void set_phyif_mode(dwc_eth_config_t *cfg)
{
if (cfg->set_phy_intf)
cfg->set_phy_intf(cfg->base, cfg->phy_intf_mode);
}
static inline void config_eth_clk(dwc_eth_config_t *cfg)
{
if (cfg->timer_sec_clk)
sdrv_ckgen_set_rate(cfg->timer_sec_clk, 125000000);
if (cfg->phy_ref_clk)
sdrv_ckgen_set_rate(cfg->phy_ref_clk, 125000000);
if (cfg->rmii_clk)
sdrv_ckgen_set_rate(cfg->rmii_clk, 50000000);
if (cfg->tx_clk)
sdrv_ckgen_set_rate(cfg->tx_clk, 250000000);
}
static inline void reset_eth(dwc_eth_config_t *cfg)
{
if (cfg->rst)
sdrv_rstgen_reset(cfg->rst);
}
static err_t dwc_eth_init(struct net_driver_s *dev)
{
int ret = 0;
int i;
dwc_eth_dev_t *eth_dev = (dwc_eth_dev_t *)dev->d_private;
dwc_eth_config_t *cfg = eth_dev->config;
struct eqos_priv *eqos;
if (eth_dev->init)
return 0;
else
eth_dev->init = true;
//set SCR ethernet operating mode, e.g. RGMII, SGMII, etc.
set_phyif_mode(cfg);
//set ethernet Clk
config_eth_clk(cfg);
//ethernet reset
reset_eth(cfg);
#if !CONFIG_ETH_USE_HEAP
struct eqos_data *eqosd = containerof(eth_dev, struct eqos_data, dev);
eqos = &eqosd->eqos;
#else
eqos = (struct eqos_priv *)malloc(sizeof(struct eqos_priv));
ASSERT(eqos);
memset(eqos, 0, sizeof(struct eqos_priv));
#endif
eqos->descs = eqos_alloc_descs(eqos, EQOS_DESCRIPTORS_NUM);
if (!eqos->descs) {
ssdk_printf(SSDK_INFO, "%s: eqos_alloc_descs() failed\n", __func__);
ret = -1;
}
eqos->tx_desc_idx = 0;
eqos->rx_desc_idx = 0;
#if !CONFIG_ETH_USE_HEAP
eqos->tx_dma_buf = eqosd->tx_dma_buf;
eqos->rx_dma_buf = eqosd->rx_dma_buf;
#else
/* Align tx dma buf base address & size to cache line to avoid tx
* dma buf corrupted by cacahe line invalidation needed by other
* address, if tx dma buf data has not been wrote to ram.
*/
#if __GNUC__
eqos->tx_dma_buf = (void *)memalign(CONFIG_ARCH_CACHE_LINE,
EQOS_TX_BUFFER_SIZE);
#else
eqos->tx_dma_buf = (void *)aligned_alloc(CONFIG_ARCH_CACHE_LINE,
EQOS_TX_BUFFER_SIZE);
#endif
ASSERT(eqos->tx_dma_buf);
memset(eqos->tx_dma_buf, 0, EQOS_TX_BUFFER_SIZE);
/* rx dma buf base address & size should be cache line aligned.
* Otherwise data before or after rx dma buf may locate in same
* cache line with rx dma buf, when invalidate rx dma buf cache,
* heap data before or after rx dma buf may be corrupted.
*/
#if __GNUC__
eqos->rx_dma_buf = (void *)memalign(CONFIG_ARCH_CACHE_LINE,
EQOS_RX_BUFFER_SIZE);
#else
eqos->rx_dma_buf = (void *)aligned_alloc(CONFIG_ARCH_CACHE_LINE,
EQOS_RX_BUFFER_SIZE);
#endif
ASSERT(eqos->rx_dma_buf);
memset(eqos->rx_dma_buf, 0, EQOS_RX_BUFFER_SIZE);
#endif
//init phy
phy_init(&eth_dev->phy_bus);
//init mac
eth_mac_init(cfg, eqos);
// set up dma tx/rx descriptors
memset(eqos->descs, 0, eqos->desc_size * EQOS_DESCRIPTORS_NUM);
for (i = 0; i < EQOS_DESCRIPTORS_TX; i++) {
struct eqos_desc *tx_desc = eqos_get_desc(eqos, i, false);
arch_clean_cache_range((addr_t)tx_desc, sizeof(struct eqos_desc));
}
for (i = 0; i < EQOS_DESCRIPTORS_RX; i++) {
struct eqos_desc *rx_desc = eqos_get_desc(eqos, i, true);
rx_desc->des0 = (paddr_t)eqos->rx_dma_buf +
(i * EQOS_MAX_PACKET_SIZE);
DMB;
rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_IOC | EQOS_DESC3_BUF1V;
arch_clean_cache_range((addr_t)rx_desc, sizeof(struct eqos_desc));
arch_invalidate_cache_range((addr_t)((char *)eqos->rx_dma_buf +
(i * EQOS_MAX_PACKET_SIZE)), EQOS_MAX_PACKET_SIZE);
}
//enable rx/tx
mac_start(cfg->base, true);
eqos->started = true;
eth_dev->eqos = eqos;
return ret;
}
static inline void eqos_rx_lock(struct eqos_priv *eqos)
{
EQOS_RX_LOCK(eqos);
}
static inline void eqos_rx_unlock(struct eqos_priv *eqos)
{
EQOS_RX_UNLOCK(eqos);
}
static inline void eqos_tx_lock(struct eqos_priv *eqos)
{
EQOS_TX_LOCK(eqos);
}
static inline void eqos_tx_unlock(struct eqos_priv *eqos)
{
EQOS_TX_UNLOCK(eqos);
}
static err_t dwc_eth_txavail(struct net_driver_s *dev, struct pbuf *p)
{
int i, ret = 0;
struct eqos_desc *tx_desc;
uint8_t *tx_buf;
uint32_t offset = 0;
struct pbuf *q = NULL;
dwc_eth_dev_t *eth_dev = (dwc_eth_dev_t *)dev->d_private;
dwc_eth_config_t *cfg = eth_dev->config;
struct eqos_priv *eqos = eth_dev->eqos;
if (p->tot_len > (cfg->mtu + ETH_FRAME_HEADER_LEN)) {
ssdk_printf(SSDK_INFO, "eth tx len > MTU, %d\n", p->tot_len);
return -1;
}
eqos_tx_lock(eqos);
tx_desc = eqos_get_desc(eqos, eqos->tx_desc_idx, false);
for (i = 0; i < 100000; i++) {
arch_invalidate_cache_range((addr_t)tx_desc, sizeof(struct eqos_desc));
if ((tx_desc->des3 & EQOS_DESC3_OWN) == 0) {
goto start_tx;
}
}
ssdk_printf(SSDK_INFO, "%s: Previous tX on desc %d timeout\n", __func__,
eqos->tx_desc_idx);
ret = -1;
goto tx_out;
start_tx:
tx_buf = (uint8_t *)eqos->tx_dma_buf +
eqos->tx_desc_idx * EQOS_MAX_PACKET_SIZE;
//copy data to pbuf
for (q = p; q != NULL; q = q->next) {
memcpy((uint8_t *)(tx_buf + offset),
(uint8_t *)((uint8_t *)q->payload), q->len);
offset += q->len;
}
arch_clean_cache_range((addr_t)tx_buf, p->tot_len);
eqos->tx_desc_idx ++;
eqos->tx_desc_idx %= EQOS_DESCRIPTORS_TX;
tx_desc->des0 = (paddr_t)tx_buf;
tx_desc->des1 = 0;
tx_desc->des2 = p->tot_len;
/*
* Make sure that if HW sees the _OWN write below, it will see all the
* writes to the rest of the descriptor too.
*/
DMB;
tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD | EQOS_DESC3_LD | (p->tot_len);
arch_clean_cache_range((addr_t)tx_desc, sizeof(struct eqos_desc));
dwmac_set_tx_tail_ptr(cfg->base,
(uint32_t)eqos_get_desc(eqos, EQOS_DESCRIPTORS_TX, false),
0);
tx_out:
eqos_tx_unlock(eqos);
return ret;
}
static uint32_t dwc_eth_getmac(struct net_driver_s *dev, void *buf, uint32_t max_len)
{
dwc_eth_dev_t *eth_dev = (dwc_eth_dev_t *)dev->d_private;
uint8_t *mac_addr = eth_dev->config->mac_addr;
if (mac_addr == NULL) {
mac_addr = dwmac_get_default_mac_addr();
}
memcpy(buf, (void *)mac_addr, max_len);
return max_len;
}
static uint32_t dwc_eth_getmtu(struct net_driver_s *dev)
{
dwc_eth_dev_t *eth_dev = (dwc_eth_dev_t *)dev->d_private;
return eth_dev->config->mtu;
}
static int dwc_eth_rx_poll(struct net_driver_s *dev)
{
struct eqos_desc *rx_desc;
uint32_t length = 0;
uint8_t *recbuf;
struct pbuf *rx_pbuf = NULL;
dwc_eth_dev_t *eth_dev = (dwc_eth_dev_t *)dev->d_private;
dwc_eth_config_t *cfg = eth_dev->config;
struct eqos_priv *eqos = eth_dev->eqos;
eqos_rx_lock(eqos);
rx_desc = eqos_get_desc(eqos, eqos->rx_desc_idx, true);
arch_invalidate_cache_range((addr_t)rx_desc, sizeof(struct eqos_desc));
if (rx_desc->des3 & EQOS_DESC3_OWN) {
eqos_rx_unlock(eqos);
return -1;
}
/*
* Make sure reading des3 before dma buffer.
* Avoid speculative reading of buffer before des3 own bit cleared.
*/
DMB;
recbuf = (uint8_t *)eqos->rx_dma_buf + (eqos->rx_desc_idx *
EQOS_MAX_PACKET_SIZE);
length = rx_desc->des3 & 0x7FFF;
arch_invalidate_cache_range((addr_t)((char *)recbuf), length);
if (length <= (cfg->mtu + ETH_FRAME_OVERHEAD_LEN)) {
rx_pbuf = pbuf_alloc(PBUF_RAW, length, PBUF_POOL);
if (rx_pbuf) {
uint32_t offset = 0;
struct pbuf *q = NULL;
for (q = rx_pbuf; q != NULL; q = q->next) {
memcpy( (uint8_t *)((uint8_t *)q->payload ), ((uint8_t *)recbuf + offset),
q->len);
offset += q->len;
}
}
}
else {
ssdk_printf(SSDK_INFO, "len > 1500! desc3 = 0x%x\n", rx_desc->des3);
}
//free packet
rx_desc->des0 = (paddr_t)recbuf;
rx_desc->des1 = 0;
rx_desc->des2 = 0;
/*
* Make sure DMA observes new des3 value after observing
* new des0 & des1 & des2 value under any condition, especially
* when des3 located in a different cache line and the cache line
* is automatically evicted due to corresponding cache set full.
*/
DMB;
rx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_IOC | EQOS_DESC3_BUF1V;
arch_clean_cache_range((addr_t)rx_desc, sizeof(struct eqos_desc));
dwmac_set_rx_tail_ptr(cfg->base,
(uint32_t)eqos_get_desc(eqos, EQOS_DESCRIPTORS_RX, true),
0);
eqos->rx_desc_idx++;
eqos->rx_desc_idx %= EQOS_DESCRIPTORS_RX;
eqos_rx_unlock(eqos);
if (rx_pbuf)
netdev_input(dev, rx_pbuf);
// if(0x40 == length)
// {
// udp_length ++;
// }
// if(50 == length) //20250113 <20><><EFBFBD><EFBFBD>
// {
// udp_length = udp_length + length;
// }
// if(50 == length) //20250113 <20><><EFBFBD><EFBFBD>
// {
// udp_length = length;
// }
// else
// {
// }
return length;
}
static inline void __dwc_eth_enable_dma_rx_int(dwc_eth_dev_t *dwc_eth)
{
for (int chn = 0; chn < ETH_MAX_DMA_CHANNEL; chn++) {
dwmac_enable_dma_rx_int(dwc_eth->config->base, chn, true);
}
}
__UNUSED static inline void __dwc_eth_disable_dma_rx_int(dwc_eth_dev_t *dwc_eth)
{
for (int chn = 0; chn < ETH_MAX_DMA_CHANNEL; chn++) {
dwmac_enable_dma_rx_int(dwc_eth->config->base, chn, false);
}
}
void dwc_eth_enable_dma_rx_int(struct net_driver_s *dev, dma_rx_int_cb_t callback)
{
ASSERT(dev);
dwc_eth_dev_t *dwc_eth = dev->d_private;
dwc_eth->rx_cb = callback;
__dwc_eth_enable_dma_rx_int(dwc_eth);
}
/**
* @brief try to read rx packet and send the packet to lwip stack.
* Should be called in thread context.
* If enable DMA rx interrupt, i.e. poll is false, this function
* should be called after DMA rx interrupt triggered. DMA rx
* interrupt will be disabled in ISR, and re-enabled in this
* function after reading out all rx packets, this is helpful to
* avoid too much rx interrupt.
*
* @param [in] dev eth device
* @param [in] poll true for polling read, false for interrupt read
* @return int total length of rx packets or -1 if rx nothing
*/
int dwc_eth_rx(struct net_driver_s *dev, bool poll)
{
ASSERT(dev);
int rx_pkt_len = 0;
int len;
do {
len = dwc_eth_rx_poll(dev);
if (len != -1)
rx_pkt_len += len;
}
while (len != -1);
if (!poll) {
dwc_eth_dev_t *dwc_eth = dev->d_private;
/* After reading all packets out, re-enable eth dma rx
* interrupt which had been disabled in rx int service
* routine. This strategy can avoid too much eth interrupt.
*/
__dwc_eth_enable_dma_rx_int(dwc_eth);
}
return rx_pkt_len ? rx_pkt_len : -1;
}
static int dwc_eth_irq_handler(uint32_t irq, void *arg)
{
struct net_driver_s *dev = arg;
dwc_eth_dev_t *dwc_eth = dev->d_private;
uint32_t reg_base = dwc_eth->config->base;
uint32_t status = dwmac_get_dma_int_status(reg_base);
uint32_t sub_sts, detail;
uint8_t chn = (irq == ENET1_SBD_INTR_NUM) ? 1 : 2;
// ssdk_printf(SSDK_DEBUG, "%s int status 0x%x\n", __func__, status);
if (!status) {
return -1;
}
if (status & (1 << 17)) {
/* MAC interrupt */
sub_sts = dwmac_get_mac_int_status(reg_base);
ssdk_printf(SSDK_EMERG, "%s %d mac int status 0x%x\n", __func__, irq, sub_sts);
if (sub_sts & (1 << 0)) {
/* RGMII/SMII PHY link status changed. Read of MAC_PHYIF_Control_Status
* register will clear the interrupt status.
*/
detail = dwmac_get_mac_phyif_control_status(reg_base);
if (detail & (1 << 19))
ssdk_printf(SSDK_EMERG, "ETH%d phy link up\n", chn);
else
ssdk_printf(SSDK_EMERG, "ETH%d phy link down\n", chn);
}
if (sub_sts & (3 << 1)) {
/* TBI/RTBI/SGMII PHY link status changed, or TBI/RTBI/SGMII PHY
* auto-negotiation is completed. Read of MAC_AN_Status register
* will clear the interrupt status.
*/
detail = dwmac_get_mac_an_status(reg_base);
ssdk_printf(SSDK_EMERG, "ETH%d mac an status 0x%x\n",
chn, detail);
}
if (sub_sts & (1 << 4)) {
/* A magic packet or Wake-on-LAN packet is received.
* Read of MAC_PMT_Control_Status register will clear
* the interrupt status.
*/
detail = dwmac_get_mac_pmt_control_status(reg_base);
ssdk_printf(SSDK_EMERG, "ETH%d mac pmt ctrl status 0x%x\n",
chn, detail);
}
if (sub_sts & (1 << 5)) {
/* LPI state entry or exit in the MAC Transmitter or Receiver.
* Read of MAC_LPI_Control_Status register will clear the
* interrupt status.
*/
detail = dwmac_get_mac_lpi_control_status(reg_base);
ssdk_printf(SSDK_EMERG, "ETH%d mac lpi ctrl status 0x%x\n",
chn, detail);
}
}
if (status & (1 << 16)) {
/* MTL interrupt */
sub_sts = dwmac_get_mtl_int_status(reg_base);
if (sub_sts & 0xFFFFFF00) {
ssdk_printf(SSDK_EMERG, "ETH%d mtl int status 0x%x\n",
chn, sub_sts);
ASSERT(0);
}
for (int i = 0; i < ETH_MAX_DMA_CHANNEL; i++) {
if (sub_sts & (1 << i)) {
detail = dwmac_get_mtl_q_int_status(reg_base, i);
dwmac_clr_mtl_q_int_status(reg_base, i, detail);
if (detail & (1 << 16))
ssdk_printf(SSDK_WARNING, "ETH%d mtl queue %d rx overflow\n",
chn, i);
if (detail & (1 << 1))
ssdk_printf(SSDK_WARNING, "ETH%d mtl queue %d ABS updated\n",
chn, i);
if (detail & (1 << 1))
ssdk_printf(SSDK_WARNING, "ETH%d mtl queue %d tx underflow\n",
chn, i);
}
}
}
if (status & 0x7F) {
/* DMA interrupt */
for (int chn = 0; chn < ETH_MAX_DMA_CHANNEL; chn++) {
sub_sts = dwmac_get_dma_chn_status(reg_base, chn);
dwmac_clear_dma_chn_int_status(reg_base, chn);
if (sub_sts & BIT(6)) {
/* DMA rx interrupt */
// ssdk_printf(SSDK_DEBUG, "%s: chn %d rx int\n", __func__, chn);
dwmac_enable_dma_rx_int(reg_base, chn, false);
if (dwc_eth->rx_cb)
dwc_eth->rx_cb(dev);
}
if (sub_sts & BIT(0)) {
/* DMA tx interrupt */
// ssdk_printf(SSDK_DEBUG, "%s: chn %d tx int\n", __func__, chn);
/* Nothing to do for now. */
}
}
}
return 0;
}
static int dwc_eqos_mdio_read(phy_bus_t *bus, uint32_t phyaddr,
uint32_t devaddr, uint32_t reg)
{
dwc_eth_dev_t *dwc_eth_dev = containerof(bus, dwc_eth_dev_t, phy_bus);
uint32_t reg_base = dwc_eth_dev->config->base;
return mac_mdio_read(reg_base, phyaddr, devaddr, reg);
}
static int dwc_eqos_mdio_write(phy_bus_t *bus, uint32_t phyaddr,
uint32_t devaddr, uint32_t reg, uint32_t data)
{
dwc_eth_dev_t *dwc_eth_dev = containerof(bus, dwc_eth_dev_t, phy_bus);
uint32_t reg_base = dwc_eth_dev->config->base;
return mac_mdio_write(reg_base, phyaddr, devaddr, reg, data);
}
static phy_bus_ops_t g_dwc_eqos_mdio_ops = {
.mdio_read = dwc_eqos_mdio_read,
.mdio_write = dwc_eqos_mdio_write
};
static void dwc_eth_phy_bus_init(phy_bus_t *bus)
{
list_initialize(&bus->phy_dev_list);
bus->ref_cnt = 0;
bus->ops = &g_dwc_eqos_mdio_ops;
}
static dwc_eth_dev_t *alloc_dwc_eth_device(void)
{
#if !CONFIG_ETH_USE_HEAP
for (int i = 0; i < MAX_ETH_CNT; i++) {
if (!g_eqos_data[i].used)
{
g_eqos_data[i].used = true;
return &g_eqos_data[i].dev;
}
}
return NULL;
#else
return (dwc_eth_dev_t *)malloc(sizeof(dwc_eth_dev_t));
#endif
}
int dwc_eth_probe(struct net_driver_s *dev, dwc_eth_config_t *cfg)
{
ASSERT(dev && cfg);
dev->d_init = dwc_eth_init;
dev->d_txavail = dwc_eth_txavail;
dev->d_getmac = dwc_eth_getmac;
dev->d_getmtu = dwc_eth_getmtu;
dwc_eth_dev_t *dw_eth_dev = alloc_dwc_eth_device();
ASSERT(dw_eth_dev);
dw_eth_dev->init = false;
dw_eth_dev->config = cfg;
dev->d_private = dw_eth_dev;
dev->d_ipaddr.addr = (cfg->ip[3] << 24) | (cfg->ip[2] << 16) |
(cfg->ip[1] << 8) | cfg->ip[0];
dev->d_netmask.addr = (cfg->mask[3] << 24) | (cfg->mask[2] << 16) |
(cfg->mask[1] << 8) | cfg->mask[0];
dev->d_gateway.addr = (1 << 24) | (cfg->ip[2] << 16) |
(cfg->ip[1] << 8) | cfg->ip[0];
dwc_eth_phy_bus_init(&dw_eth_dev->phy_bus);
for (int i = 0; cfg->phy[i].phy_addr != ~0; i++) {
phy_dev_register(&dw_eth_dev->phy_bus, &cfg->phy[i]);
}
External_wdt_refresh();
int ret = netdev_register(dev, NET_LL_ETHERNET);
External_wdt_refresh();
irq_attach(cfg->irq_num, dwc_eth_irq_handler, dev);
irq_enable(cfg->irq_num);
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,638 @@
/**
* dw_mac_lld.h
*
* Copyright (c) 2021 Semidrive Semiconductor.
* All rights reserved.
*
* Description: dw eth mac lld header file
*
* Revision History:
* -----------------
*/
#ifndef _DW_MAC_LLD_H_
#define _DW_MAC_LLD_H_
#ifndef BIT
#define BIT(n) (1U << (n))
#endif
#ifndef GENMASK
#define GENMASK(h, l) \
(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (32 - 1 - (h))))
#endif
/* MAC reg */
#define MAC_CONFIG 0x00000000
#define MAC_PACKET_FILTER 0x00000008
#define MAC_HASH_TAB_0_31 0x00000010
#define MAC_HASH_TAB_32_63 0x00000014
#define MAC_HASH_TAB_64_95 0x00000018
#define MAC_HASH_TAB_96_127 0x0000001c
#define MAC_RX_FLOW_CTRL 0x00000090
#define MAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4)
#define MAC_TXQ_PRTY_MAP0 0x98
#define MAC_TXQ_PRTY_MAP1 0x9C
#define MAC_RXQ_CTRL0 0x000000a0
#define MAC_RXQ_CTRL1 0x000000a4
#define MAC_RXQ_CTRL2 0x000000a8
#define MAC_RXQ_CTRL3 0x000000ac
#define MAC_INT_STATUS 0x000000b0
#define MAC_INT_EN 0x000000b4
#define MAC_RX_TX_STATUS 0x000000b8
#define MAC_PMT_CONTROL_STATUS 0x000000c0
#define MAC_LPI_CONTROL_STATUS 0x000000d0
#define MAC_1US_TIC_COUNTER 0x000000dc
#define MAC_PCS_BASE 0x000000e0
#define MAC_AN_STATUS 0x000000e4
#define MAC_PHYIF_CONTROL_STATUS 0x000000f8
#define MAC_PMT 0x000000c0
#define MAC_VERSION 0x00000110
#define MAC_DEBUG 0x00000114
#define MAC_HW_FEATURE0 0x0000011c
#define MAC_HW_FEATURE1 0x00000120
#define MAC_HW_FEATURE2 0x00000124
#define MAC_HW_FEATURE3 0x00000128
#define MAC_MDIO_ADDR 0x00000200
#define MAC_MDIO_DATA 0x00000204
#define MAC_ADDR_HIGH(reg) (0x300 + reg * 8)
#define MAC_ADDR_LOW(reg) (0x304 + reg * 8)
/* Rx Stats */
#define MAC_PACKETS_RX_CONUT_64 0x000007ac
#define MAC_PACKETS_RX_CONUT_65_127 0x000007b0
#define MAC_PACKETS_RX_CONUT_128_255 0x000007b4
#define MAC_PACKETS_RX_CONUT_256_511 0x000007b8
#define MAC_PACKETS_RX_CONUT_512_1023 0x000007bc
#define MAC_PACKETS_RX_CONUT_1024_MAX 0x000007c0
#define MAC_PACKETS_RX_CONUT_UNICAST 0x000007c4
#define MAC_PACKETS_RX_CONUT_MULTICAST 0x00000790
#define MAC_PACKETS_RX_CONUT_BROADCAST 0x0000078c
#define MAC_PACKETS_RX_CONUT_ALL_BYTES 0x00000784
#define MAC_PACKETS_RX_CONUT_ALL_PKT 0x00000780
#define MAC_PACKETS_RX_CONUT_BAD_PKT 0x000007e0
#define MAC_PACKETS_RX_CONUT_CRC_ERR 0x00000794
#define MAC_PACKETS_RX_CONUT_FRAG_ERR 0x0000079C
#define MAC_PACKETS_RX_CONUT_ALIGN_ERR 0x00000798
#define MAC_PACKETS_RX_CONUT_JABBER_ERR 0x000007a0
#define MAC_PACKETS_RX_CONUT_UNDER_PKT 0x000007a4
#define MAC_PACKETS_RX_CONUT_OVER_PKT 0x000007a8
#define MAC_PACKETS_RX_CONUT_DROP_PKT 0x000007d4
#define MAC_PACKETS_RX_CONUT_MIIDROP_PKT 0x000007e0
/* Tx Stats */
#define MAC_PACKETS_TX_CONUT_ALL_BYTES 0x00000714
#define MAC_PACKETS_TX_CONUT_UNICAST 0x0000073C
#define MAC_PACKETS_TX_CONUT_BROADCAST 0x00000744
#define MAC_PACKETS_TX_CONUT_MULTICAST 0x00000740
#define MAC_PACKETS_TX_CONUT_SINGL_COLL 0x0000074C
#define MAC_PACKETS_TX_CONUT_MULT_COLL 0x00000750
#define MAC_PACKETS_TX_CONUT_DFRD_COLL 0x00000754
#define MAC_PACKETS_TX_CONUT_LATE_COLL 0x00000758
#define MAC_PACKETS_TX_CONUT_OVER_PKT 0x00000778
#define MAC_PACKETS_TX_CONUT_ALL_PKT 0x00000718
#define MAC_PACKETS_TX_CONUT_GOOD_PKT 0x00000768
#define MAC_PACKETS_TX_CONUT_DROP_PKT_COLL 0x0000075c
#define MAC_PACKETS_TX_CONUT_DROP_PKT_CARR 0x00000760
#define MAC_PACKETS_TX_CONUT_ERR_PKT 0x0000076c
#define MMC_RX_INTERRUPT_MASK 0x70C
#define MMC_TX_INTERRUPT_MASK 0x710
#define MMC_IPC_RX_INTERRUPT_MASK 0x800
/* RX Queues Routing */
#define MAC_RXQCTRL_AVCPQ_MASK GENMASK(2, 0)
#define MAC_RXQCTRL_AVCPQ_SHIFT 0
#define MAC_RXQCTRL_PTPQ_MASK GENMASK(6, 4)
#define MAC_RXQCTRL_PTPQ_SHIFT 4
#define MAC_RXQCTRL_DCBCPQ_MASK GENMASK(10, 8)
#define MAC_RXQCTRL_DCBCPQ_SHIFT 8
#define MAC_RXQCTRL_UPQ_MASK GENMASK(14, 12)
#define MAC_RXQCTRL_UPQ_SHIFT 12
#define MAC_RXQCTRL_MCBCQ_MASK GENMASK(18, 16)
#define MAC_RXQCTRL_MCBCQ_SHIFT 16
#define MAC_RXQCTRL_MCBCQEN BIT(20)
#define MAC_RXQCTRL_MCBCQEN_SHIFT 20
#define MAC_RXQCTRL_TACPQE BIT(21)
#define MAC_RXQCTRL_TACPQE_SHIFT 21
/* MAC Packet Filtering */
#define MAC_PACKET_FILTER_PR BIT(0)
#define MAC_PACKET_FILTER_HUC BIT(1)
#define MAC_PACKET_FILTER_HMC BIT(2)
#define MAC_PACKET_FILTER_DAIF BIT(3)
#define MAC_PACKET_FILTER_PM BIT(4)
#define MAC_PACKET_FILTER_DBF BIT(5)
#define MAC_PACKET_FILTER_MASK GENMASK(7, 6)
#define MAC_PACKET_FILTER_SHIFT (6)
#define MAC_PACKET_FILTER_HPF BIT(10)
#define MAC_PACKET_FILTER_PA BIT(31)
#define MAC_MAX_PERFECT_ADDRESSES 128
/* MAC RX Queue Enable */
#define MAC_RX_QUEUE_CLEAR(queue) ~(GENMASK(1, 0) << ((queue) * 2))
#define MAC_RX_AV_QUEUE_ENABLE(queue) BIT((queue) * 2)
#define MAC_RX_DCB_QUEUE_ENABLE(queue) BIT(((queue) * 2) + 1)
/* MAC Flow Control RX */
#define MAC_RX_FLOW_CTRL_RFE BIT(0)
/* RX Queues Priorities */
#define MAC_RXQCTRL_PSRQX_MASK(x) GENMASK(7 + ((x) * 8), 0 + ((x) * 8))
#define MAC_RXQCTRL_PSRQX_SHIFT(x) ((x) * 8)
/* TX Queues Priorities */
#define MAC_TXQCTRL_PSTQX_MASK(x) GENMASK(7 + ((x) * 8), 0 + ((x) * 8))
#define MAC_TXQCTRL_PSTQX_SHIFT(x) ((x) * 8)
/* MAC Flow Control TX */
#define MAC_TX_FLOW_CTRL_TFE BIT(1)
#define MAC_TX_FLOW_CTRL_PT_SHIFT 16
/* MAC Interrupt bitmap*/
#define MAC_INT_RGSMIIS BIT(0)
#define MAC_INT_PCS_LINK BIT(1)
#define MAC_INT_PCS_ANE BIT(2)
#define MAC_INT_PCS_PHYIS BIT(3)
#define MAC_INT_PMT_EN BIT(4)
#define MAC_INT_LPI_EN BIT(5)
#define MAC_PCS_IRQ_DEFAULT (MAC_INT_RGSMIIS | MAC_INT_PCS_LINK | MAC_INT_PCS_ANE)
#define MAC_INT_DEFAULT_ENABLE (MAC_INT_PMT_EN | MAC_INT_LPI_EN)
/* MAC config */
#define MAC_CONFIG_IPC BIT(27)
#define MAC_CONFIG_2K BIT(22)
#define MAC_CONFIG_ACS BIT(20)
#define MAC_CONFIG_WD BIT(19)
#define MAC_CONFIG_BE BIT(18)
#define MAC_CONFIG_JD BIT(17)
#define MAC_CONFIG_JE BIT(16)
#define MAC_CONFIG_PS BIT(15)
#define MAC_CONFIG_FES BIT(14)
#define MAC_CONFIG_DM BIT(13)
#define MAC_CONFIG_DCRS BIT(9)
#define MAC_CONFIG_TE BIT(1)
#define MAC_CONFIG_RE BIT(0)
/* MAC HW ADDR regs */
#define MAC_HI_DCS GENMASK(18, 16)
#define MAC_HI_DCS_SHIFT 16
#define MAC_HI_REG_AE BIT(31)
/* MTL registers */
#define MTL_OPERATION_MODE 0x00000c00
#define MTL_OPERATION_SCHALG_MASK GENMASK(6, 5)
#define MTL_OPERATION_SCHALG_WRR (0x0 << 5)
#define MTL_OPERATION_SCHALG_WFQ (0x1 << 5)
#define MTL_OPERATION_SCHALG_DWRR (0x2 << 5)
#define MTL_OPERATION_SCHALG_SP (0x3 << 5)
#define MTL_OPERATION_RAA BIT(2)
#define MTL_OPERATION_RAA_SP (0x0 << 2)
#define MTL_OPERATION_RAA_WSP (0x1 << 2)
#define MTL_TX_OPERATION_TSF BIT(2)
#define MTL_TX_OPERATION_TQ GENMASK(3, 2)
#define MTL_TX_OPERATION_TQ_EN (0x2 << 2)
#define MTL_TX_OPERATION_TQ_DIS (0x0 << 2)
#define MTL_TX_CONFIG_FLAGS_TQ BIT(3)
#define MTL_INT_STATUS 0x00000c20
#define MTL_INT_QX(x) BIT(x)
#define MTL_RXQ_DMA_MAP0 0x00000c30 /* queue 0 to 3 */
#define MTL_RXQ_DMA_MAP1 0x00000c34 /* queue 4 to 7 */
#define MTL_RXQ_DMA_Q04MDMACH_MASK GENMASK(3, 0)
#define MTL_RXQ_DMA_Q04MDMACH(x) ((x) << 0)
#define MTL_RXQ_DMA_QXMDMACH_MASK(x) GENMASK(11 + (8 * ((x) - 1)), 8 * (x))
#define MTL_RXQ_DMA_QXMDMACH(channel, q) ((channel) << (8 * (q)))
#define MTL_ECC_CTRL 0xcc0
#define MTL_ECC_DEFAULT_ENABLE 0xf
#define MTL_DPP_CTRL 0x00000ce0
#define MTL_DPP_CTRL_DATA_PARITY BIT(0)
#define MTL_DPP_CTRL_SLAVE_PARITY BIT(2)
#define MTL_CHAN_BASE_ADDR 0x00000d00
#define MTL_CHAN_BASE_OFFSET 0x40
#define MTL_CHANX_BASE_ADDR(x) (MTL_CHAN_BASE_ADDR + \
(x * MTL_CHAN_BASE_OFFSET))
#define MTL_CHAN_TX_OP_MODE(x) MTL_CHANX_BASE_ADDR(x)
#define MTL_CHAN_TX_DEBUG(x) (MTL_CHANX_BASE_ADDR(x) + 0x8)
#define MTL_CHAN_INT_CTRL(x) (MTL_CHANX_BASE_ADDR(x) + 0x2c)
#define MTL_CHAN_RX_OP_MODE(x) (MTL_CHANX_BASE_ADDR(x) + 0x30)
#define MTL_CHAN_RX_DEBUG(x) (MTL_CHANX_BASE_ADDR(x) + 0x38)
#define MTL_OP_MODE_RSF BIT(5)
#define MTL_OP_MODE_TXQEN_MASK GENMASK(3, 2)
#define MTL_OP_MODE_TXQEN_AV BIT(2)
#define MTL_OP_MODE_TXQEN BIT(3)
#define MTL_OP_MODE_TSF BIT(1)
#define MTL_OP_MODE_TQS_MASK GENMASK(24, 16)
#define MTL_OP_MODE_TQS_SHIFT 16
#define MTL_OP_MODE_TTC_MASK 0x70
#define MTL_OP_MODE_TTC_SHIFT 4
#define MTL_OP_MODE_TTC_32 0
#define MTL_OP_MODE_TTC_64 (1 << MTL_OP_MODE_TTC_SHIFT)
#define MTL_OP_MODE_TTC_96 (2 << MTL_OP_MODE_TTC_SHIFT)
#define MTL_OP_MODE_TTC_128 (3 << MTL_OP_MODE_TTC_SHIFT)
#define MTL_OP_MODE_TTC_192 (4 << MTL_OP_MODE_TTC_SHIFT)
#define MTL_OP_MODE_TTC_256 (5 << MTL_OP_MODE_TTC_SHIFT)
#define MTL_OP_MODE_TTC_384 (6 << MTL_OP_MODE_TTC_SHIFT)
#define MTL_OP_MODE_TTC_512 (7 << MTL_OP_MODE_TTC_SHIFT)
#define MTL_OP_MODE_RQS_MASK GENMASK(29, 20)
#define MTL_OP_MODE_RQS_SHIFT 20
#define MTL_OP_MODE_RFD_MASK GENMASK(19, 14)
#define MTL_OP_MODE_RFD_SHIFT 14
#define MTL_OP_MODE_RFA_MASK GENMASK(13, 8)
#define MTL_OP_MODE_RFA_SHIFT 8
#define MTL_OP_MODE_FEP BIT(4)
#define MTL_OP_MODE_FUP BIT(3)
#define MTL_OP_MODE_EHFC BIT(7)
#define MTL_OP_MODE_RTC_MASK 0x18
#define MTL_OP_MODE_RTC_SHIFT 3
#define MTL_OP_MODE_RTC_32 (1 << MTL_OP_MODE_RTC_SHIFT)
#define MTL_OP_MODE_RTC_64 0
#define MTL_OP_MODE_RTC_96 (2 << MTL_OP_MODE_RTC_SHIFT)
#define MTL_OP_MODE_RTC_128 (3 << MTL_OP_MODE_RTC_SHIFT)
/* MTL ETS Control register */
#define MTL_ETS_CTRL_BASE_ADDR 0x00000d10
#define MTL_ETS_CTRL_BASE_OFFSET 0x40
#define MTL_ETSX_CTRL_BASE_ADDR(x) (MTL_ETS_CTRL_BASE_ADDR + \
((x) * MTL_ETS_CTRL_BASE_OFFSET))
#define MTL_ETS_CTRL_CC BIT(3)
#define MTL_ETS_CTRL_AVALG BIT(2)
/* MTL Queue Quantum Weight */
#define MTL_TXQ_WEIGHT_BASE_ADDR 0x00000d18
#define MTL_TXQ_WEIGHT_BASE_OFFSET 0x40
#define MTL_TXQX_WEIGHT_BASE_ADDR(x) (MTL_TXQ_WEIGHT_BASE_ADDR + \
((x) * MTL_TXQ_WEIGHT_BASE_OFFSET))
#define MTL_TXQ_WEIGHT_ISCQW_MASK GENMASK(20, 0)
/* MTL sendSlopeCredit register */
#define MTL_SEND_SLP_CRED_BASE_ADDR 0x00000d1c
#define MTL_SEND_SLP_CRED_OFFSET 0x40
#define MTL_SEND_SLP_CREDX_BASE_ADDR(x) (MTL_SEND_SLP_CRED_BASE_ADDR + \
((x) * MTL_SEND_SLP_CRED_OFFSET))
#define MTL_SEND_SLP_CRED_SSC_MASK GENMASK(13, 0)
/* MTL hiCredit register */
#define MTL_HIGH_CRED_BASE_ADDR 0x00000d20
#define MTL_HIGH_CRED_OFFSET 0x40
#define MTL_HIGH_CREDX_BASE_ADDR(x) (MTL_HIGH_CRED_BASE_ADDR + \
((x) * MTL_HIGH_CRED_OFFSET))
#define MTL_HIGH_CRED_HC_MASK GENMASK(28, 0)
/* MTL loCredit register */
#define MTL_LOW_CRED_BASE_ADDR 0x00000d24
#define MTL_LOW_CRED_OFFSET 0x40
#define MTL_LOW_CREDX_BASE_ADDR(x) (MTL_LOW_CRED_BASE_ADDR + \
((x) * MTL_LOW_CRED_OFFSET))
#define MTL_HIGH_CRED_LC_MASK GENMASK(28, 0)
/* MTL interrupt */
#define MTL_RX_OVERFLOW_INT_EN BIT(24)
#define MTL_RX_OVERFLOW_INT BIT(16)
#define MTL_TX_UNDEROVERFLOW_INT BIT(0)
/* Default operating mode of the MAC */
#define MAC_CORE_INIT (MAC_CONFIG_JD | MAC_CONFIG_PS | \
MAC_CONFIG_BE | MAC_CONFIG_DCRS | MAC_CONFIG_DM)
/* To dump the core regs excluding the Address Registers */
#define MAC_REG_NUM 0x300
/* MTL algorithms identifiers */
#define MTL_TX_ALGORITHM_WRR 0x0
#define MTL_TX_ALGORITHM_WFQ 0x1
#define MTL_TX_ALGORITHM_DWRR 0x2
#define MTL_TX_ALGORITHM_SP 0x3
#define MTL_RX_ALGORITHM_SP 0x4
#define MTL_RX_ALGORITHM_WSP 0x5
/* RX/TX Queue Mode */
#define MTL_QUEUE_MODE_AVB 0x1
#define MTL_QUEUE_MODE_DCB 0x2
#define SF_MODE 1
#define MAC_FITER_PASS_ALL 0
#define MAC_FITER_PASS_MULTICAST 1
#define MAC_FITER_PASS_HASH_MULTICAST 2
#define MAC_FITER_PASS_UNICAST 3
#define ERDES4_MSG_TYPE_MASK GENMASK(11, 8)
/* Extended RDES4 message type definitions */
#define RDES_EXT_NO_PTP 0x0
#define RDES_EXT_SYNC 0x1
#define RDES_EXT_FOLLOW_UP 0x2
#define RDES_EXT_DELAY_REQ 0x3
#define RDES_EXT_DELAY_RESP 0x4
#define RDES_EXT_PDELAY_REQ 0x5
#define RDES_EXT_PDELAY_RESP 0x6
#define RDES_EXT_PDELAY_FOLLOW_UP 0x7
#define RDES_PTP_ANNOUNCE 0x8
#define RDES_PTP_MANAGEMENT 0x9
#define RDES_PTP_SIGNALING 0xa
#define RDES_PTP_PKT_RESERVED_TYPE 0xf
/* Rx IPC status */
enum rx_frame_status {
RX_GOOD = 0x0,
RX_BAD = 0x1,
RX_DMA_PROCESS = 0x8,
csum_none = 0x2,
llc_snap = 0x4,
rx_not_ls = 0x10,
};
enum tx_frame_status {
TX_GOOD = 0x0,
TX_ERROR = 0x1,
TX_DMA_PROCESS = 0x2,
TX_NOT_LS = 0x3,
};
/* DMA config */
#define ETH_MAX_DMA_CHANNEL 1
#define DMA_BUS_MODE 0x00001000
#define DMA_STATUS 0x00001008
#define DMA_SYS_BUS_MODE 0x00001004
#define DMA_DEBUG_STATUS_0 0x0000100c
#define DMA_DEBUG_STATUS_1 0x00001010
#define DMA_DEBUG_STATUS_2 0x00001014
#define DMA_AXI_BUS_MODE 0x00001028
enum dma_rx_status {
DMX_RX_STOP = 0,
DMX_RX_RUN_FRTD,
DMX_RX_RSVD,
DMX_RX_WRP,
DMX_RX_SUSPND,
DMX_RX_RUN_CRD,
DMX_RX_TSTMP,
DMX_RX_TRP
};
/* DMA Bus Mode bitmap */
#define DMA_BUS_MODE_SFT_RESET BIT(0)
/* DMA SYS Bus Mode bitmap */
#define DMA_BUS_MODE_SPH BIT(24)
#define DMA_BUS_MODE_PBL BIT(16)
#define DMA_BUS_MODE_PBL_SHIFT 16
#define DMA_BUS_MODE_RPBL_SHIFT 16
#define DMA_BUS_MODE_MB BIT(14)
#define DMA_BUS_MODE_FB BIT(0)
/* DMA Interrupt top status */
#define DMA_STATUS_MAC BIT(17)
#define DMA_STATUS_MTL BIT(16)
#define DMA_STATUS_CHAN7 BIT(7)
#define DMA_STATUS_CHAN6 BIT(6)
#define DMA_STATUS_CHAN5 BIT(5)
#define DMA_STATUS_CHAN4 BIT(4)
#define DMA_STATUS_CHAN3 BIT(3)
#define DMA_STATUS_CHAN2 BIT(2)
#define DMA_STATUS_CHAN1 BIT(1)
#define DMA_STATUS_CHAN0 BIT(0)
#define DMA_STATUS_CHAN0_5 GENMASK(4,0)
/* DMA debug status bitmap */
#define DMA_DEBUG_STATUS_TS_MASK 0xf
#define DMA_DEBUG_STATUS_RS_MASK 0xf
/* DMA AXI bitmap */
#define DMA_AXI_EN_LPI BIT(31)
#define DMA_AXI_LPI_XIT_FRM BIT(30)
#define DMA_AXI_WR_OSR_LMT GENMASK(27, 24)
#define DMA_AXI_WR_OSR_LMT_SHIFT 24
#define DMA_AXI_RD_OSR_LMT GENMASK(19, 16)
#define DMA_AXI_RD_OSR_LMT_SHIFT 16
#define DMA_AXI_OSR_MAX 0xf
#define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
(DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
#define DMA_SYS_BUS_MB BIT(14)
#define DMA_AXI_1KBBE BIT(13)
#define DMA_SYS_BUS_AAL BIT(12)
#define DMA_SYS_BUS_EAME BIT(11)
#define DMA_AXI_BLEN256 BIT(7)
#define DMA_AXI_BLEN128 BIT(6)
#define DMA_AXI_BLEN64 BIT(5)
#define DMA_AXI_BLEN32 BIT(4)
#define DMA_AXI_BLEN16 BIT(3)
#define DMA_AXI_BLEN8 BIT(2)
#define DMA_AXI_BLEN4 BIT(1)
#define DMA_SYS_BUS_FB BIT(0)
#define DMA_BURST_LEN_DEFAULT (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \
DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \
DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \
DMA_AXI_BLEN4)
#define DMA_AXI_BURST_LEN_MASK 0x000000FE
/* Following DMA defines are chanels oriented */
#define DMA_CHAN_BASE_ADDR 0x00001100
#define DMA_CHAN_BASE_OFFSET 0x80
#define DMA_CHANX_BASE_ADDR(x) (DMA_CHAN_BASE_ADDR + (x * DMA_CHAN_BASE_OFFSET))
#define DMA_CHAN_REG_NUMBER 17
#define DMA_CHAN_CONTROL(x) DMA_CHANX_BASE_ADDR(x)
#define DMA_CHAN_TX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x4)
#define DMA_CHAN_RX_CONTROL(x) (DMA_CHANX_BASE_ADDR(x) + 0x8)
#define DMA_CHAN_TX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x10)
#define DMA_CHAN_TX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x14)
#define DMA_CHAN_RX_BASE_ADDR_HI(x) (DMA_CHANX_BASE_ADDR(x) + 0x18)
#define DMA_CHAN_RX_BASE_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x1c)
#define DMA_CHAN_TX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x20)
#define DMA_CHAN_RX_END_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x28)
#define DMA_CHAN_TX_RING_LEN(x) (DMA_CHANX_BASE_ADDR(x) + 0x2c)
#define DMA_CHAN_RX_RING_LEN(x) (DMA_CHANX_BASE_ADDR(x) + 0x30)
#define DMA_CHAN_INTR_ENA(x) (DMA_CHANX_BASE_ADDR(x) + 0x34)
#define DMA_CHAN_RX_WATCHDOG(x) (DMA_CHANX_BASE_ADDR(x) + 0x38)
#define DMA_CHAN_SLOT_CTRL_STATUS(x) (DMA_CHANX_BASE_ADDR(x) + 0x3c)
#define DMA_CHAN_CUR_TX_DESC(x) (DMA_CHANX_BASE_ADDR(x) + 0x44)
#define DMA_CHAN_CUR_RX_DESC(x) (DMA_CHANX_BASE_ADDR(x) + 0x4c)
#define DMA_CHAN_CUR_TX_BUF_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x54)
#define DMA_CHAN_CUR_RX_BUF_ADDR(x) (DMA_CHANX_BASE_ADDR(x) + 0x5c)
#define DMA_CHAN_STATUS(x) (DMA_CHANX_BASE_ADDR(x) + 0x60)
/* DMA Control X */
#define DMA_CONTROL_MSS_MASK GENMASK(13, 0)
/* DMA Tx channel X Control register defines */
#define DMA_CONTROL_DSL_MASK GENMASK(20, 18)
#define DMA_CONTROL_DSL_SHIFT 18
#define DMA_CONTROL_TSE BIT(12)
#define DMA_CONTROL_OSP BIT(4)
#define DMA_CONTROL_ST BIT(0)
#define DMA_CONTROL_TXPBL(x) (((x) << 16) & GENMASK(21, 16))
/* DMA Rx channel X Control register defines */
#define DMA_CONTROL_SR BIT(0)
#define DMA_RBSZ_MASK GENMASK(14, 1)
#define DMA_RBSZ_SHIFT 1
#define DMA_CONTROL_RXPBL(x) (((x) << 16) & GENMASK(21, 16))
/* Interrupt status per channel */
#define DMA_CHAN_STATUS_REB GENMASK(21, 19)
#define DMA_CHAN_STATUS_REB_SHIFT 19
#define DMA_CHAN_STATUS_TEB GENMASK(18, 16)
#define DMA_CHAN_STATUS_TEB_SHIFT 16
#define DMA_CHAN_STATUS_NIS BIT(15)
#define DMA_CHAN_STATUS_AIS BIT(14)
#define DMA_CHAN_STATUS_CDE BIT(13)
#define DMA_CHAN_STATUS_FBE BIT(12)
#define DMA_CHAN_STATUS_ERI BIT(11)
#define DMA_CHAN_STATUS_ETI BIT(10)
#define DMA_CHAN_STATUS_RWT BIT(9)
#define DMA_CHAN_STATUS_RPS BIT(8)
#define DMA_CHAN_STATUS_RBU BIT(7)
#define DMA_CHAN_STATUS_RI BIT(6)
#define DMA_CHAN_STATUS_TBU BIT(2)
#define DMA_CHAN_STATUS_TPS BIT(1)
#define DMA_CHAN_STATUS_TI BIT(0)
/* Interrupt enable bits per channel */
#define DMA_CHAN_INTR_ENA_NIE BIT(15)
#define DMA_CHAN_INTR_ENA_AIE BIT(14)
#define DMA_CHAN_INTR_ENA_CDE BIT(13)
#define DMA_CHAN_INTR_ENA_FBE BIT(12)
#define DMA_CHAN_INTR_ENA_ERE BIT(11)
#define DMA_CHAN_INTR_ENA_ETE BIT(10)
#define DMA_CHAN_INTR_ENA_RWE BIT(9)
#define DMA_CHAN_INTR_ENA_RSE BIT(8)
#define DMA_CHAN_INTR_ENA_RBUE BIT(7)
#define DMA_CHAN_INTR_ENA_RIE BIT(6)
#define DMA_CHAN_INTR_ENA_TBUE BIT(2)
#define DMA_CHAN_INTR_ENA_TSE BIT(1)
#define DMA_CHAN_INTR_ENA_TIE BIT(0)
#define DMA_CHAN_INTR_NORMAL (DMA_CHAN_INTR_ENA_NIE | \
DMA_CHAN_INTR_ENA_RIE | \
DMA_CHAN_INTR_ENA_TIE )
#define DMA_CHAN_INTR_ABNORMAL (DMA_CHAN_INTR_ENA_AIE | \
DMA_CHAN_INTR_ENA_FBE)
/* DMA default interrupt mask for 4.00 */
#define DMA_CHAN_INTR_DEFAULT_MASK (DMA_CHAN_INTR_NORMAL | \
DMA_CHAN_INTR_ABNORMAL)
#define PHY_CLAUSE_22 0xFF
static inline void udelay(uint32_t usecs)
{
volatile uint64_t count = usecs * 300;
while (count > 0)
count--;
}
/*
mode transmit store and forward enable or not
qmode transmit queue enable or not
fifo transmit queue size
*/
#if defined(DEBUG_ENABLE)
void dwmac_dump_mac(uint32_t addr);
void dwmac_dump_mtl(uint32_t regbase, uint32_t queue);
#endif
void dwmac_prog_mtl_rx_algorithms(uint32_t regbase, uint32_t rx_alg);
void dwmac_prog_mtl_tx_algorithms(uint32_t regbase, uint32_t tx_alg);
void dwmac_map_mtl_dma(uint32_t addr, uint32_t queue, uint32_t channel);
int32_t dwmac_set_filter(uint32_t regbase, uint32_t mode,
const uint8_t *mac_addr);
void dwmac_flow_ctrl(uint32_t regbase, uint32_t duplex, uint32_t fc,
uint32_t pause_time, uint32_t tx_cnt);
void dwmac_core_init(uint32_t regbase, uint32_t mtu, uint32_t speed,
uint8_t *macaddr);
void dwmac_clr_umac_addr(uint32_t regbase, uint32_t Reg_n);
void dwmac_set_umac_addr(uint32_t regbase, const uint8_t *addr,
uint32_t reg_n);
void dwmac_get_umac_addr(uint32_t regbase, uint8_t *addr, uint32_t reg_n);
void dwmac_rx_queue_enable(uint32_t addr, uint8_t mode, uint32_t queue);
int dwmac_irq_mtl_status(uint32_t regbase, uint32_t channel);
int32_t dwmac_dma_reset(uint32_t regbase);
bool dwmac_access_test(uint32_t regbase);
void dwmac_enable_dma_irq(uint32_t regbase, uint32_t channel, bool rx,
bool tx);
void dwmac_disable_dma_irq(uint32_t regbase, uint32_t channel);
void dwmac_dump_dma_regs(uint32_t regbase, int channel);
void dwmac_dma_start_tx(uint32_t regbase, uint32_t channel);
void dwmac_dma_stop_tx(uint32_t regbase, uint32_t channel);
void dwmac_dma_start_rx(uint32_t regbase, uint32_t channel);
void dwmac_dma_stop_rx(uint32_t regbase, uint32_t channel);
void dwmac_dma_rx_chan_op_mode(uint32_t regbase, uint32_t channel, int mode,
int fifosz, uint8_t qmode);
/*
mode transmit store and forward enable or not
qmode transmit queue enable or not
fifo transmit queue size
*/
void dwmac_dma_tx_chan_op_mode(uint32_t regbase, uint32_t channel, int mode,
int fifosz, uint8_t qmode);
void dwmac_set_rx_ring_len(uint32_t regbase, uint32_t len, uint32_t channel);
void dwmac_set_tx_ring_len(uint32_t regbase, uint32_t len, uint32_t channel);
void dwmac_set_rx_list_ptr(uint32_t regbase, uint32_t list_ptr,
uint32_t channel);
void dwmac_set_tx_list_ptr(uint32_t regbase, uint32_t list_ptr,
uint32_t channel);
void dwmac_set_rx_tail_ptr(uint32_t regbase, uint32_t tail_ptr,
uint32_t channel);
void dwmac_set_tx_tail_ptr(uint32_t regbase, uint32_t tail_ptr,
uint32_t channel);
void dwmac_dma_init_rx_chan(uint32_t regbase, uint32_t base_ptr,
uint32_t rbsz, uint32_t channel);
void dwmac_dma_init_tx_chan(uint32_t regbase, uint32_t base_ptr,
uint32_t channel);
void dwmac_dma_bus_init(uint32_t regbase, uint32_t flags);
uint32_t dwmac_dma_rx_state_get(uint32_t regbase, uint32_t channel);
void dwmac_dma_init_channel(uint32_t regbase, uint32_t flags, \
uint32_t channel, uint32_t skip);
void dwmac_set_bfsize(uint32_t regbase, int bfsize, uint32_t channel);
int32_t mac_mdio_write(uint32_t regbase, uint8_t phyaddr, uint8_t device,
uint16_t phyreg, uint16_t phydata);
int32_t mac_mdio_read(uint32_t regbase, uint8_t phyaddr, uint8_t device,
uint16_t phyreg);
void dwmac_rx_trigger(uint32_t regbase, uint32_t channel);
void dwmac_mac_rx_queue_mcbc_routing(uint32_t regbase, uint8_t channel);
uint8_t *dwmac_get_default_mac_addr(void);
void dwmac_enable_dma_rx_int(uint32_t regbase, uint32_t channel, bool enable);
void dwmac_enable_dma_tx_int(uint32_t regbase, uint32_t channel, bool enable);
uint32_t dwmac_get_dma_int_status(uint32_t regbase);
uint32_t dwmac_get_mac_int_status(uint32_t regbase);
uint32_t dwmac_get_mac_phyif_control_status(uint32_t regbase);
uint32_t dwmac_get_mac_an_status(uint32_t regbase);
uint32_t dwmac_get_mac_pmt_control_status(uint32_t regbase);
uint32_t dwmac_get_mac_lpi_control_status(uint32_t regbase);
uint32_t dwmac_get_mtl_int_status(uint32_t regbase);
uint32_t dwmac_get_mtl_q_int_status(uint32_t regbase, uint32_t channel);
void dwmac_clr_mtl_q_int_status(uint32_t regbase, uint32_t channel, uint32_t val);
uint32_t dwmac_get_dma_chn_status(uint32_t regbase, uint32_t channel);
void dwmac_clear_dma_chn_int_status(uint32_t regbase, uint32_t channel);
#endif