/*
* Copyright (C) 2020-2021 Suzhou Tiancheng Software Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* ls1x_gmac.c
*
* Loongson1x GMAC driver
* GMAC work with MII, support 10/100M, fullduplex/halfduplex mode.
*
* created: 2013/07/01
* author: Bian
*
*/
#include "bsp.h"
#if defined(BSP_USE_GMAC0) || defined(BSP_USE_GMAC1)
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#if defined(LS1B)
#include "ls1b.h"
#include "ls1b_irq.h"
#elif defined(LS1C)
#include "ls1c.h"
#include "ls1c_irq.h"
#else
#error "No Loongson1x SoC defined!"
#endif
#if defined(OS_RTTHREAD)
#include "rtthread.h"
#elif defined(OS_UCOS)
#include "os.h"
#elif defined(OS_FREERTOS)
#include "FreeRTOS.h"
#include "event_groups.h"
#endif
#include "cpu.h"
#include "mii.h"
#include "ls1x_io.h"
#include "drv_os_priority.h"
#include "ls1x_gmac_hw.h"
#include "ls1x_gmac.h"
//***************************************************************************************
#define GMAC_DEBUG 0 // 调试
#define GMAC_TRACE_INFO 1 // print some message
//***************************************************************************************
#define LS1x_K0_CACHED 1
#ifdef LS1x_K0_CACHED
#define VA_TO_PHYS(x) K1_TO_PHYS(x)
#else
#define VA_TO_PHYS(x) K0_TO_PHYS(x)
#endif
#define GMAC_BUF_CACHED 1 // buffer cached
#ifndef ETHER_MAX_LEN
#define ETHER_MAX_LEN 1518 // should defined by tcp/ip stack
#endif
#define MAX_BUF_SIZE 1536 // 48*32, reference by ETHER_MAX_LEN=1518
#define DMA_DESC_SIZE 32
#define NUM_TX_DMA_DESC 4 // TX 描述符个数, 和 TX 缓冲区个数一致
#define NUM_RX_DMA_DESC 4 // RX 描述符个数, 和 RX 缓冲区个数一致
#define TX_BUF_SIZE MAX_BUF_SIZE // TX 缓冲区大小
#define RX_BUF_SIZE MAX_BUF_SIZE // RX 缓冲区大小
#define MII_WR_TIMEOUT 0x0200 // mii write timeout
#define MII_RD_TIMEOUT 0x0200 // mii read timeout
#define GDMA_RESET_TIMEOUT 0x0200 // gdma reset timeout
//***************************************************************************************
// Hardware-specific storage, 驱动专用硬件相关的控制结构
//***************************************************************************************
typedef struct
{
LS1x_gmac_regs_t *hwGMAC; /* GMAC Hardware */
LS1x_gdma_regs_t *hwGDMA;
unsigned int phyAddr; /* PHY Address */
unsigned int gmacVersion; /* 设备版本号 */
unsigned int vector; /* GMAC Interrupt Registers */
unsigned int int_ctrlr;
unsigned int int_mask;
int unitNumber; /* 设备号 */
int acceptBroadcast; /* Indicates configuration */
int autoNegotiation; /* 是否自动协商 */
int autoNegoTimeout; /* 自动协商超时 ms */
unsigned int LinkState; /* Link status as reported by the Phy */
unsigned int DuplexMode; /* Duplex mode of the Phy */
unsigned int Speed; /* Speed of the Phy */
unsigned int descmode; /* DMA Desc Mode chain or ring */
LS1x_rxdesc_t *rx_desc[NUM_RX_DMA_DESC]; /* RX 描述符指针数组 */
LS1x_txdesc_t *tx_desc[NUM_TX_DMA_DESC]; /* TX 描述符指针数组 */
int rx_head;
int rx_tail;
int tx_head;
int tx_tail;
unsigned char *rx_buf[NUM_RX_DMA_DESC]; /* RX 缓冲区指针数组 */
unsigned char *tx_buf[NUM_TX_DMA_DESC]; /* TX 缓冲区指针数组 */
#if defined(OS_RTTHREAD)
rt_event_t gmac_event;
#elif defined(OS_UCOS)
OS_FLAG_GRP *gmac_event;
#elif defined(OS_FREERTOS)
EventGroupHandle_t gmac_event;
#endif
unsigned int interrupts; /* Statistics 统计数 */
unsigned int dma_normal_intrs;
unsigned int dma_abnormal_intrs;
unsigned int dma_fatal_err;
unsigned int rx_interrupts;
unsigned int tx_interrupts;
unsigned int rx_pkts;
unsigned int rx_buffer_unavailable;
unsigned int rx_stopped;
unsigned int rx_errors;
unsigned int rx_length_err;
unsigned int rx_dribit_err;
unsigned int rx_dropped;
unsigned int tx_pkts;
unsigned int tx_buffer_unavailable;
unsigned int tx_stopped;
unsigned int tx_errors;
unsigned int tx_ipheader_err;
unsigned int tx_playload_err;
unsigned int tx_defered;
unsigned int tx_collsions;
unsigned int tx_underflow;
int timeout; /* 收发超时 */
int initialized; /* 是否初始化 */
int started; /* 是否启动 */
char dev_name[16]; /* 设备名称 */
} GMAC_t;
//***************************************************************************************
// ls1x gmac device and buffer
//***************************************************************************************
#define __ALIGN(x) __attribute__((aligned(x)))
#if defined(BSP_USE_GMAC0)
static GMAC_t ls1x_GMAC0 =
{
#if defined(LS1B)
.hwGMAC = (LS1x_gmac_regs_t *)LS1B_GMAC0_BASE,
.hwGDMA = (LS1x_gdma_regs_t *)LS1x_GDMA0_BASE,
.int_ctrlr = LS1B_INTC1_BASE,
.int_mask = INTC1_GMAC0_BIT,
.vector = LS1B_GMAC0_IRQ,
#elif defined(LS1C)
.hwGMAC = (LS1x_gmac_regs_t *)LS1C_MAC_BASE,
.hwGDMA = (LS1x_gdma_regs_t *)LS1x_GDMA0_BASE,
.int_ctrlr = LS1C_INTC1_BASE,
.int_mask = INTC1_MAC_BIT,
.vector = LS1C_MAC_IRQ,
#endif
.unitNumber = 0,
.descmode = CHAINMODE, // XXX This is important
.timeout = 0,
.started = 0,
.initialized = 0,
.dev_name = "gmac0",
.acceptBroadcast = 0,
.autoNegotiation = 1,
.autoNegoTimeout = 3000,
};
void *devGMAC0 = (void *)&ls1x_GMAC0;
static unsigned char tx_desc_0[(NUM_TX_DMA_DESC*DMA_DESC_SIZE)] __ALIGN(32);
static unsigned char rx_desc_0[(NUM_RX_DMA_DESC*DMA_DESC_SIZE)] __ALIGN(32);
static unsigned char tx_buf_0[(NUM_TX_DMA_DESC*TX_BUF_SIZE)] __ALIGN(32);
static unsigned char rx_buf_0[(NUM_RX_DMA_DESC*RX_BUF_SIZE)] __ALIGN(32);
#endif
#if defined(BSP_USE_GMAC1)
static GMAC_t ls1x_GMAC1 =
{
.hwGMAC = (LS1x_gmac_regs_t *)LS1B_GMAC1_BASE,
.hwGDMA = (LS1x_gdma_regs_t *)LS1B_GDMA1_BASE,
.int_ctrlr = LS1B_INTC1_BASE,
.int_mask = INTC1_GMAC1_BIT,
.vector = LS1B_GMAC1_IRQ,
.unitNumber = 1,
.descmode = CHAINMODE, // XXX This is important
.timeout = 0,
.started = 0,
.initialized = 0,
.dev_name = "gmac1",
.acceptBroadcast = 0,
.autoNegotiation = 1,
.autoNegoTimeout = 3000,
};
void *devGMAC1 = (void *)&ls1x_GMAC1;
static unsigned char tx_desc_1[(NUM_TX_DMA_DESC*DMA_DESC_SIZE)] __ALIGN(32);
static unsigned char rx_desc_1[(NUM_RX_DMA_DESC*DMA_DESC_SIZE)] __ALIGN(32);
static unsigned char tx_buf_1[(NUM_TX_DMA_DESC*TX_BUF_SIZE)] __ALIGN(32);
static unsigned char rx_buf_1[(NUM_RX_DMA_DESC*RX_BUF_SIZE)] __ALIGN(32);
#endif
//***************************************************************************************
// function prototypes
//***************************************************************************************
static int LS1x_init_tx_desc_queue(GMAC_t *pMAC);
static int LS1x_init_rx_desc_queue(GMAC_t *pMAC);
static void LS1x_GMAC_init_hw(GMAC_t *pMAC, unsigned char *macAddr);
static void LS1x_GMAC_irq_handler(int vector, void *arg);
static void LS1x_GMAC_do_reset(GMAC_t *pMAC);
//***************************************************************************************
// functions for gdma desc
//***************************************************************************************
static inline void GDMA_INIT_RXDESC(GMAC_t *pMAC)
{
LS1x_init_rx_desc_queue(pMAC);
pMAC->rx_head = 0;
pMAC->rx_tail = 0;
}
static inline void GDMA_INIT_TXDESC(GMAC_t *p
评论10