blob: 1dc1f98a6e148ce2e98d55408aba913dacc18986 [file] [log] [blame]
/*
* Copyright 2017, NXP
* Copyright 2017, Data61, CSIRO (ABN 41 687 119 230)
* Copyright 2020, HENSOLDT Cyber GmbH
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include "enet.h"
#include "io.h"
#include <platsupport/clock.h>
#include "unimplemented.h"
#include "../../debug.h"
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#ifdef CONFIG_PLAT_IMX8MQ_EVK
#define CCM_PADDR 0x30380000
#define CCM_SIZE 0x10000
#endif
#define ENET_FREQ 125000000UL
#define MDC_FREQ 20000000UL /* must be less than 2.5MHz */
struct mib_regs {
/* NOTE: Counter not implemented because it is not applicable (read 0 always).*/
uint32_t rmon_t_drop; /* 00 Register Count of frames not counted correctly */
uint32_t rmon_t_packets; /* 04 RMON Tx packet count */
uint32_t rmon_t_bc_pkt; /* 08 RMON Tx Broadcast Packets */
uint32_t rmon_t_mc_pkt; /* 0C RMON Tx Multicast Packets */
uint32_t rmon_t_crc_align; /* 10 RMON Tx Packets w CRC/Align error */
uint32_t rmon_t_undersize; /* 14 RMON Tx Packets < 64 bytes, good CRC */
uint32_t rmon_t_oversize; /* 18 RMON Tx Packets > MAX_FL bytes, good CRC */
uint32_t rmon_t_frag; /* 1C RMON Tx Packets < 64 bytes, bad CRC */
uint32_t rmon_t_jab; /* 20 RMON Tx Packets > MAX_FL bytes, bad CRC*/
uint32_t rmon_t_col; /* 24 RMON Tx collision count */
uint32_t rmon_t_p64; /* 28 RMON Tx 64 byte packets */
uint32_t rmon_t_p65to127n; /* 2C RMON Tx 65 to 127 byte packets */
uint32_t rmon_t_p128to255n; /* 30 RMON Tx 128 to 255 byte packets */
uint32_t rmon_t_p256to511; /* 34 RMON Tx 256 to 511 byte packets */
uint32_t rmon_t_p512to1023; /* 38 RMON Tx 512 to 1023 byte packets */
uint32_t rmon_t_p1024to2047; /* 3C RMON Tx 1024 to 2047 byte packets */
uint32_t rmon_t_p_gte2048; /* 40 RMON Tx packets w > 2048 bytes */
uint32_t rmon_t_octets; /* 44 RMON Tx Octets */
/* NOTE: Counter not implemented because it is not applicable (read 0 always). */
uint32_t ieee_t_drop; /* 48 Count of frames not counted correctly */
uint32_t ieee_t_frame_ok; /* 4C Frames Transmitted OK */
uint32_t ieee_t_1col; /* 50 Frames Transmitted with Single Collision */
uint32_t ieee_t_mcol; /* 54 Frames Transmitted with Multiple Collisions */
uint32_t ieee_t_def; /* 58 Frames Transmitted after Deferral Delay */
uint32_t ieee_t_lcol; /* 5C Frames Transmitted with Late Collision */
uint32_t ieee_t_excol; /* 60 Frames Transmitted with Excessive Collisions */
uint32_t ieee_t_macerr; /* 64 Frames Transmitted with Tx FIFO Underrun */
uint32_t ieee_t_cserr; /* 68 Frames Transmitted with Carrier Sense Error */
/* NOTE: Counter not implemented because there is no SQE information available (read 0 always). */
uint32_t ieee_t_sqe; /* 6C Frames Transmitted with SQE Error */
uint32_t ieee_t_fdxfc; /* 70 Flow Control Pause frames transmitted */
/* NOTE: Counts total octets (includes header and FCS fields). */
uint32_t ieee_t_octets_ok; /* 74 Octet count for Frames Transmitted w/o Error */
uint32_t res0[3];
uint32_t rmon_r_packets; /* 84 RMON Rx packet count */
uint32_t rmon_r_bc_pkt; /* 88 RMON Rx Broadcast Packets */
uint32_t rmon_r_mc_pkt; /* 8C RMON Rx Multicast Packets */
uint32_t rmon_r_crc_align; /* 90 RMON Rx Packets w CRC/Align error */
uint32_t rmon_r_undersize; /* 94 RMON Rx Packets < 64 bytes, good CRC */
uint32_t rmon_r_oversize; /* 98 RMON Rx Packets > MAX_FL, good CRC */
uint32_t rmon_r_frag; /* 9C RMON Rx Packets < 64 bytes, bad CRC */
uint32_t rmon_r_jab; /* A0 RMON Rx Packets > MAX_FL bytes, bad CRC */
uint32_t rmon_r_resvd_0; /* A4 Reserved */
uint32_t rmon_r_p64; /* A8 RMON Rx 64 byte packets */
uint32_t rmon_r_p65to127; /* AC RMON Rx 65 to 127 byte packets */
uint32_t rmon_r_p128to255; /* B0 RMON Rx 128 to 255 byte packets */
uint32_t rmon_r_p256to511; /* B4 RMON Rx 256 to 511 byte packets */
uint32_t rmon_r_p512to1023; /* B8 RMON Rx 512 to 1023 byte packets */
uint32_t rmon_r_p1024to2047; /* BC RMON Rx 1024 to 2047 byte packets */
uint32_t rmon_r_p_gte2048; /* C0 RMON Rx packets w > 2048 bytes */
uint32_t rmon_r_octets; /* C4 RMON Rx Octets */
/* NOTE: Counter increments if a frame with invalid/missing SFD character is
* detected and has been dropped. None of the other counters increments if
* this counter increments. */
uint32_t ieee_r_drop; /* C8 Count of frames not counted correctly */
uint32_t ieee_r_frame_ok; /* CC Frames Received OK */
uint32_t ieee_r_crc; /* D0 Frames Received with CRC Error */
uint32_t ieee_r_align; /* D4 Frames Received with Alignment Error */
/* Assume they mean D8... */
uint32_t ieee_r_macerr; /* D7 Receive FIFO Overflow count */
uint32_t ieee_r_fdxfc; /* DC Flow Control Pause frames received */
/* NOTE: Counts total octets (includes header and FCS fields ) */
uint32_t ieee_r_octets_ok; /* E0 Octet count for Frames Rcvd w/o Error */
uint32_t res1[7];
};
struct enet_regs {
/* Configuration */
uint32_t res0[1];
uint32_t eir; /* 004 Interrupt Event Register */
uint32_t eimr; /* 008 Interrupt Mask Register */
uint32_t res1[1];
uint32_t rdar; /* 010 Receive Descriptor Active Register */
uint32_t tdar; /* 014 Transmit Descriptor Active Register */
uint32_t res2[3];
uint32_t ecr; /* 024 Ethernet Control Register */
uint32_t res3[6];
uint32_t mmfr; /* 040 MII Management Frame Register */
uint32_t mscr; /* 044 MII Speed Control Register */
uint32_t res4[7];
uint32_t mibc; /* 064 MIB Control Register */
uint32_t res5[7];
uint32_t rcr; /* 084 Receive Control Register */
uint32_t res6[15];
uint32_t tcr; /* 0C4 Transmit Control Register */
uint32_t res7[7];
uint32_t palr; /* 0E4 Physical Address Lower Register */
uint32_t paur; /* 0E8 Physical Address Upper Register */
uint32_t opd; /* 0EC Opcode/Pause Duration Register */
uint32_t res8[10];
uint32_t iaur; /* 118 Descriptor Individual Upper Address Register */
uint32_t ialr; /* 11C Descriptor Individual Lower Address Register */
uint32_t gaur; /* 120 Descriptor Group Upper Address Register */
uint32_t galr; /* 124 Descriptor Group Lower Address Register */
uint32_t res9[7];
uint32_t tfwr; /* 144 Transmit FIFO Watermark Register */
uint32_t res10[14];
uint32_t rdsr; /* 180 Receive Descriptor Ring Start Register */
uint32_t tdsr; /* 184 Transmit Buffer Descriptor Ring Start Register */
uint32_t mrbr; /* 188 Maximum Receive Buffer Size Register */
uint32_t res12[1];
uint32_t rsfl; /* 190 Receive FIFO Section Full Threshold */
uint32_t rsem; /* 194 Receive FIFO Section Empty Threshold */
uint32_t raem; /* 198 Receive FIFO Almost Empty Threshold */
uint32_t rafl; /* 19C Receive FIFO Almost Full Threshold */
uint32_t tsem; /* 1A0 Transmit FIFO Section Empty Threshold */
uint32_t taem; /* 1A4 Transmit FIFO Almost Empty Threshold */
uint32_t tafl; /* 1A8 Transmit FIFO Almost Full Threshold */
uint32_t tipg; /* 1AC Transmit Inter-Packet Gap */
uint32_t ftrl; /* 1B0 Frame Truncation Length */
uint32_t res13[3];
uint32_t tacc; /* 1C0 Transmit Accelerator Function Configuration */
uint32_t racc; /* 1C4 Receive Accelerator Function Configuration */
uint32_t res14[14];
/* 0x200: Statistics counters MIB block RFC 2819 */
struct mib_regs mib;
uint32_t res15[64];
/* 0x400: 1588 adjustable timer (TSM) and 1588 frame control */
uint32_t atcr; /* 400 Timer Control Register */
uint32_t atvr; /* 404 Timer Value Register */
uint32_t atoff; /* 408 Timer Offset Register */
uint32_t atper; /* 40C Timer Period Register */
uint32_t atcor; /* 410 Timer Correction Register */
uint32_t atinc; /* 414 Time-Stamping Clock Period Register */
uint32_t atstmp; /* 418 Timestamp of Last Transmitted Frame */
uint32_t res16[121];
/* 0x600: Capture/compare block */
uint32_t res17[1];
uint32_t tgsr; /* 604 Timer Global Status Register */
uint32_t tcsr0; /* 608 Timer Control Status Register */
uint32_t tccr0; /* 60C Timer Compare Capture Register */
uint32_t tcsr1; /* 610 Timer Control Status Register */
uint32_t tccr1; /* 614 Timer Compare Capture Register */
uint32_t tcsr2; /* 618 Timer Control Status Register */
uint32_t tccr2; /* 61C Timer Compare Capture Register */
uint32_t tcsr3; /* 620 Timer Control Status Register */
uint32_t tccr3; /* 624 Timer Compare Capture Register */
};
typedef volatile struct enet_regs enet_regs_t;
struct enet {
enet_regs_t regs;
};
static inline enet_regs_t *enet_get_regs(struct enet *enet)
{
return &(enet->regs);
}
/* Ethernet control register */
#define ECR_DBSWP BIT(8) /* descriptor byte swapping enable */
#define ECR_STOPEN BIT(7) /* Disable ENET clock in doze mode */
#define ECR_DBGEN BIT(6) /* Harware freeze when in debug mode */
#define ECR_SPEED BIT(5) /* Enable 1000Mbps */
#define ECR_EN1588 BIT(4) /* Enhanced descriptors */
#define ECR_SLEEP BIT(3) /* Enter sleep mode */
#define ECR_MAGICEN BIT(2) /* Magic packet detection enable */
#define ECR_ETHEREN BIT(1) /* Enable */
#define ECR_RESET BIT(0) /* Reset */
/* Receive control register */
#define RCR_GRS BIT(31) /* Graceful Receive Stopped */
#define RCR_NLC BIT(30) /* No payload Length Check */
#define RCR_MAX_FL(x) (((x) & 0x3fff) << 16) /* Maximum Frame Length */
#define RCR_CFEN BIT(15) /* MAC Control Frame Enable */
#define RCR_CRCSTRIP BIT(14) /* Do not Forward Received CRC */
#define RCR_PAUFWD BIT(13) /* Forward Pause Frames */
#define RCR_PADEN BIT(12) /* Frame padding enable */
#define RCR_RMII_10T BIT( 9) /* 10 Mbps */
#define RCR_RMII_MODE BIT( 8) /* RMII Mode Enable */
#define RCR_RGMII_EN BIT( 6) /* RGMII Mode Enable. RMII must not be set */
#define RCR_FCE BIT( 5) /* Flow control enable */
#define RCR_BC_REJ BIT( 4) /* Broadcast frame reject */
#define RCR_PROM BIT( 3) /* Promiscuous mode */
#define RCR_MII_MODE BIT( 2) /* This field must always be set */
#define RCR_DRT BIT( 1) /* Don't receive while transmitting (half duplex) */
#define RCR_LOOP BIT( 0) /* internal loop back */
/* Transmit control register */
#define TCR_CRCINS BIT( 9) /* Insert CRC on transit */
#define TCR_ADDINS BIT( 8) /* Insert MAC address on transit */
#define TCR_ADDSEL(x) (((x) & 0x7) << 5) /* MAC select (supports only 0) */
#define TCR_RFCPAUSE BIT(4) /* Received a pause frame */
#define TCR_TFCPAUSE BIT(3) /* Transmit pause frame after the current frame completes */
#define TCR_FDEN BIT(2) /* Full duplex enable */
#define TCR_GTS BIT(0) /* Graceful TX stop */
/* Receive Accelerator Function Configuration */
#define RACC_LINEDIS BIT(6) /* Discard frames with MAC layer errors */
/* Transmit FIFO watermark */
#define TFWR_STRFWD BIT( 8) /* Enables store and forward */
/* MIB control */
#define MIBC_DIS BIT(31) /* Disable MIB counters */
#define MIBC_IDLE BIT(30) /* MIB currently updating a counter */
#define MIBC_CLEAR BIT(29) /* Clear all counters */
/* RX descriptor active */
#define RDAR_RDAR BIT(24) /* RX descriptor active */
/* TX descriptor active */
#define TDAR_TDAR BIT(24) /* TX descriptor active */
/* TODO this should be defined elsewhere */
#define FRAME_LEN 1518
#define PAUSE_FRAME_TYPE_FIELD 0x8808 /* fixed magic */
#define PAUSE_OPCODE_FIELD 0x0001 /* Fixed magic opcode used when sending pause frames */
/* configurable */
#define PAUSE_DURATION 32 /* Pause duration field when sending pause frames */
#define STRFWD_BYTES 128 /* Number of bytes in buffer before transmission begins */
#define TIPG 8 /* TX inter-packet gap between 8 and 27 bytes */
#define PHYOP_VALID (BIT(30) | BIT(17))
#define PHYOP_READ BIT(29)
#define PHYOP_WRITE BIT(28)
#define PHYOP_PHY_SHIFT 23
#define PHYOP_REG_SHIFT 18
#define PHYOP_DATA_SHIFT 0
/******************
*** MDIO clock ***
******************/
static freq_t _mdc_clk_get_freq(clk_t *clk)
{
enet_regs_t *regs = (enet_regs_t *)clk->priv;
uint32_t fin = clk_get_freq(clk->parent);
uint32_t v = (regs->mscr >> 1) & 0x3f;
uint32_t fout = fin / ((v + 1) * 2);
return fout;
}
static freq_t _mdc_clk_set_freq(clk_t *clk, freq_t hz)
{
enet_regs_t *regs = (enet_regs_t *)clk->priv;
uint32_t fin = clk_get_freq(clk->parent);
uint32_t v;
if (hz > 2500000UL) {
hz = 2500000UL;
} else if (hz == 0) {
hz = 1;
}
v = fin / (2 * hz) - 1;
if (v == -1) {
v = 0;
} else if (v > 0x3f) {
v = 0x3f;
}
regs->mscr = v << 1;
ZF_LOGD("Set MDC frequency to %u Hz (<= 2.5 Mhz)", clk_get_freq(clk));
return clk_get_freq(clk);
}
static void _mdc_clk_recal(struct clock *clk)
{
assert(0);
}
static clk_t *_mdc_clk_init(clk_t *clk)
{
return clk;
}
static struct clock mdc_clk = {
.id = CLK_CUSTOM,
.name = "mdc_clk",
.priv = NULL,
.req_freq = 2500000UL,
.set_freq = &_mdc_clk_set_freq,
.get_freq = &_mdc_clk_get_freq,
.recal = &_mdc_clk_recal,
.init = &_mdc_clk_init,
.parent = NULL,
.sibling = NULL,
.child = NULL,
};
#ifdef CONFIG_PLAT_IMX8MQ_EVK
static freq_t _enet_clk_get_freq(clk_t *clk)
{
return clk->req_freq;
}
static struct clock enet_clk = {
.id = CLK_CUSTOM,
.name = "enet_clk",
.priv = NULL,
.req_freq = 125000000UL,
.set_freq = NULL,
.get_freq = &_enet_clk_get_freq,
.recal = NULL,
.init = NULL,
.parent = NULL,
.sibling = NULL,
.child = NULL,
};
#endif
void enet_set_speed(struct enet *enet, int speed, int full_duplex)
{
enet_regs_t *regs = enet_get_regs(enet);
uint32_t ecr = regs->ecr;
uint32_t rcr = regs->rcr;
/* RGMII mode */
rcr &= ~RCR_RMII_MODE;
rcr |= RCR_RGMII_EN | RCR_MII_MODE;
/* Now select speed */
switch (speed) {
case 1000:
ecr |= ECR_SPEED;
rcr &= ~RCR_RMII_10T;
break;
case 100:
ecr &= ~ECR_SPEED;
rcr &= ~RCR_RMII_10T;
break;
case 10:
ecr &= ~ECR_SPEED;
rcr |= RCR_RMII_10T;
break;
default:
ZF_LOGE("Invalid speed");
assert(0);
return;
}
/* Now select duplex */
if (full_duplex) {
rcr &= ~RCR_DRT;
} else {
rcr |= RCR_DRT;
}
/* Write the registers */
regs->ecr = ecr;
regs->rcr = rcr;
}
/****************
*** MDIO bus ***
****************/
int enet_mdio_read(struct enet *enet, uint16_t phy, uint16_t reg)
{
enet_regs_t *regs = enet_get_regs(enet);
uint32_t v;
assert(!(phy & ~0x1f));
assert(!(reg & ~0x1f));
assert(regs->mscr);
assert(!enet_clr_events(enet, NETIRQ_MII));
v = phy << PHYOP_PHY_SHIFT | reg << PHYOP_REG_SHIFT;
v |= PHYOP_READ | PHYOP_VALID;
writel(v, &regs->mmfr);
while (!enet_clr_events(enet, NETIRQ_MII)) {
dsb();
}
return readl(&regs->mmfr) & 0xffff;
}
int enet_mdio_write(struct enet *enet, uint16_t phy, uint16_t reg,
uint16_t data)
{
enet_regs_t *regs = enet_get_regs(enet);
uint32_t v;
assert(!(phy & ~0x1f));
assert(!(reg & ~0x1f));
assert(regs->mscr);
assert(!enet_clr_events(enet, NETIRQ_MII));
v = phy << PHYOP_PHY_SHIFT | reg << PHYOP_REG_SHIFT | data;
v |= PHYOP_WRITE | PHYOP_VALID;
regs->mmfr = v;
while (!enet_clr_events(enet, NETIRQ_MII));
return 0;
}
/*******************
*** ENET driver ***
*******************/
void enet_rx_enable(struct enet *enet)
{
enet_get_regs(enet)->rdar = RDAR_RDAR;
}
int enet_rx_enabled(struct enet *enet)
{
return enet_get_regs(enet)->rdar == RDAR_RDAR;
}
int enet_tx_enabled(struct enet *enet)
{
return enet_get_regs(enet)->tdar == TDAR_TDAR;
}
void enet_tx_enable(struct enet *enet)
{
enet_get_regs(enet)->tdar = TDAR_TDAR;
}
void enet_enable(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
regs->ecr |= ECR_ETHEREN;
}
int enet_enabled(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
return (regs->ecr & ECR_ETHEREN) != 0;
}
void enet_disable(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
assert(!"WARNING Descriptors will be reset");
regs->ecr &= ~ECR_ETHEREN;
}
void enet_set_mac(struct enet *enet, uint64_t mac)
{
enet_regs_t *regs = enet_get_regs(enet);
/* We get the MAC as uint64_t, the value 0x0000<aa><bb><cc><dd><ee><ff>
* corresponds to the MAC aa:bb:cc:dd:ee:ff. The registers are set up as
* PALR = 0x<aa><bb><cc><dd>
* MAC byte 0 in bits 31:24
* MAC byte 1 in bits 23:16
* MAC byte 2 in bits 15:8
* MAC byte 3 in bits 7:0
* PAUR = 0x<ee><ff><xxxx>
* MAC byte 4 in bits 31:24
* MAC byte 5 in bits 23:16
*/
regs->palr = (uint32_t)(mac >> 16);
regs->paur = (((uint32_t)mac & 0xffff) << 16) | PAUSE_FRAME_TYPE_FIELD;
}
uint64_t enet_get_mac(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
/* The MAC aa:bb:cc:dd:ee:ff is stored in
* PALR = 0x<aa><bb><cc><dd>
* PAUR = 0x<ee><ff><xxxx>
* We return it as uint64_t 0x0000<aa><bb><cc><dd><ee><ff>
*/
return (((uint64_t)regs->palr) << 16) | (regs->paur >> 16);
}
void enet_enable_events(struct enet *enet, uint32_t mask)
{
assert(enet);
enet_get_regs(enet)->eimr = mask;
}
uint32_t enet_get_events(struct enet *enet)
{
return enet_get_regs(enet)->eir;
}
uint32_t enet_clr_events(struct enet *enet, uint32_t bits)
{
enet_regs_t *regs = enet_get_regs(enet);
uint32_t e = regs->eir & bits;
/* write 1 to clear */
regs->eir = e;
return e;
}
void enet_prom_enable(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
regs->rcr |= RCR_PROM;
}
void enet_prom_disable(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
regs->rcr &= ~RCR_PROM;
}
void enet_crc_strip_enable(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
regs->rcr |= RCR_CRCSTRIP;
}
void enet_crc_strip_disable(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
regs->rcr &= ~RCR_CRCSTRIP;
}
struct enet *enet_init(void *mapped_peripheral, uintptr_t tx_phys,
uintptr_t rx_phys, size_t rx_bufsize, uint64_t mac,
ps_io_ops_t *io_ops)
{
assert(mapped_peripheral);
struct clock *enet_clk_ptr = NULL;
/* The enet device is simply the register mapping */
struct enet *enet = (struct enet *)mapped_peripheral;
enet_regs_t *regs = enet_get_regs(enet);
/* Perform reset */
regs->ecr = ECR_RESET;
while (regs->ecr & ECR_RESET);
regs->ecr |= ECR_DBSWP;
/* Clear and mask interrupts */
regs->eimr = 0x00000000;
regs->eir = 0xffffffff;
#if defined(CONFIG_PLAT_IMX6)
/* Set the ethernet clock frequency */
clock_sys_t *clk_sys = malloc(sizeof(clock_sys_t));
clock_sys_init(io_ops, clk_sys);
enet_clk_ptr = clk_get_clock(clk_sys, CLK_ENET);
clk_set_freq(enet_clk_ptr, ENET_FREQ);
#elif defined(CONFIG_PLAT_IMX8MQ_EVK)
enet_clk_ptr = &enet_clk;
// TODO Implement an actual clock driver for the imx8mq
void *clock_base = RESOURCE(&io_ops->io_mapper, CCM);
if (!clock_base) {
ZF_LOGE("clock controller could not be mapped");
return NULL;
}
uint32_t *ccgr_enet_set = clock_base + 0x40a0;
uint32_t *ccgr_enet_clr = clock_base + 0x40a4;
uint32_t *ccgr_sim_enet_set = clock_base + 0x4400;
uint32_t *ccgr_sim_enet_clr = clock_base + 0x4404;
/* Gate the clocks first */
*ccgr_enet_clr = 0x3;
*ccgr_sim_enet_clr = 0x3;
/* Setup the clocks to have the proper sources/configs */
uint32_t *enet_axi_target = clock_base + 0x8880;
uint32_t *enet_ref_target = clock_base + 0xa980;
uint32_t *enet_timer_target = clock_base + 0xaa00;
*enet_axi_target = BIT(28) | 0x01000000; // ENABLE | MUX SYS1_PLL | POST AND PRE DIVIDE BY 1
*enet_ref_target = BIT(28) | 0x01000000; // ENABLE | MUX PLL2_DIV8 | POST AND PRE DIVIDE BY 1
*enet_timer_target = BIT(28) | 0x01000000 | ((4) & 0x3f); // ENABLE | MUX PLL2_DIV10 | POST DIVIDE BY 4, PRE DIVIDE BY 1
/* Ungate the clocks now */
*ccgr_enet_set = 0x3;
*ccgr_sim_enet_set = 0x3;
#endif
/* Set the MDIO clock frequency */
mdc_clk.priv = (void *)regs;
clk_register_child(enet_clk_ptr, &mdc_clk);
clk_set_freq(&mdc_clk, MDC_FREQ);
/* Clear out MIB */
enet_clear_mib(enet);
/* Descriptor group and individual hash tables - Not changed on reset */
regs->iaur = 0;
regs->ialr = 0;
regs->gaur = 0;
regs->galr = 0;
/* Set MAC and pause frame type field */
enet_set_mac(enet, mac);
/* Configure pause frames (continues into MAC registers...) */
regs->opd = PAUSE_OPCODE_FIELD << 16;
#ifdef PAUSE_DURATION
if (PAUSE_DURATION >= 0) {
regs->opd |= PAUSE_DURATION << 0;
}
#endif
/* TX inter-packet gap */
regs->tipg = TIPG;
/* Transmit FIFO Watermark register - store and forward */
regs->tfwr = 0;
#ifdef STRFWD_BYTES
if (STRFWD_BYTES > 0) {
regs->tfwr = STRFWD_BYTES / 64;
regs->tfwr |= TFWR_STRFWD;
}
#endif
/* Do not forward frames with errors */
regs->racc = RACC_LINEDIS;
/* DMA descriptors */
regs->tdsr = (uint32_t)tx_phys;
regs->rdsr = (uint32_t)rx_phys;
regs->mrbr = (uint32_t)rx_bufsize;
/* Receive control - Set frame length and RGMII mode */
regs->rcr = RCR_MAX_FL(FRAME_LEN) | RCR_RGMII_EN | RCR_MII_MODE;
/* Transmit control - Full duplex mode */
regs->tcr = TCR_FDEN;
return enet;
}
/****************************
*** Debug and statistics ***
****************************/
static void dump_regs(uint32_t *start, int size)
{
uint32_t *base = start;
for (unsigned int i = 0; i < size / sizeof(*start);) {
printf("+0x%03x: ", ((uint32_t)(start - base)) * 4);
for (unsigned int j = 0; j < 4; j++, i++, start++) {
printf("0x%08x ", *start);
}
printf("\n");
}
}
void enet_dump_regs(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
printf("\nEthernet regs\n");
dump_regs((uint32_t *)regs, sizeof(*regs));
printf("\n");
}
void enet_clear_mib(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
/* Disable */
regs->mibc |= MIBC_DIS;
while (!(regs->mibc & MIBC_IDLE));
/* Clear */
regs->mibc |= MIBC_CLEAR;
while (!(regs->mibc & MIBC_IDLE));
/* Restart */
regs->mibc &= ~MIBC_CLEAR;
regs->mibc &= ~MIBC_DIS;
}
void enet_print_mib(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
volatile struct mib_regs *mib = &regs->mib;
regs->mibc |= MIBC_DIS;
printf("Ethernet Counter regs\n");
dump_regs((uint32_t *)mib, sizeof(*mib));
printf("\n");
printf("-----------------------------\n");
printf("RX Frames RX OK: %d/%d\n", mib->ieee_r_frame_ok,
mib->rmon_r_packets);
printf("RX FIFO overflow: %d\n", mib->ieee_r_macerr);
printf("RX pause frames: %d\n", mib->ieee_r_fdxfc);
printf("-----------------------------\n");
printf("TX Frames TX OK: %d/%d\n", mib->ieee_t_frame_ok,
mib->rmon_t_packets);
printf("TX FIFO underrun: %d\n", mib->ieee_t_macerr);
printf("TX pause frames: %d\n", mib->ieee_t_fdxfc);
printf("-----------------------------\n");
printf("\n");
regs->mibc &= ~MIBC_DIS;
}
void enet_print_state(struct enet *enet)
{
enet_regs_t *regs = enet_get_regs(enet);
printf("Ethernet state: %s\n", (enet_enabled(enet)) ? "Active" : "Inactive");
printf(" TX state: %s\n", (enet_tx_enabled(enet)) ? "Active" : "Inactive");
printf(" RX state: %s\n", (enet_rx_enabled(enet)) ? "Active" : "Inactive");
printf(" TX control: 0x%08x\n", regs->tcr);
printf(" RX control: 0x%08x\n", regs->rcr);
printf(" RX desc base: 0x%08x (size: 0x%x)\n", regs->rdsr, regs->mrbr);
printf(" TX desc base: 0x%08x\n", regs->tdsr);
printf("Enabled events: 0x%08x\n", regs->eimr);
printf("Pending events: 0x%08x\n", regs->eir);
printf(" Speed: ????\n");
printf("\n");
}