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 @@
obj-y += net_drv.o mii_drv.o ctrl.o glb.o mac.o mdio.o sys.o
@@ -0,0 +1,139 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __BSPETH_H__
#define __BSPETH_H__
#include <config.h>
#include <common.h>
#include <command.h>
#include <linux/list.h>
#include <asm/io.h>
#include <malloc.h> /* malloc, free, realloc */
#include <net.h>
#include <miiphy.h>
#include <asm/arch/platform.h>
#define OSDRV_MODULE_VERSION_STRING "ETH net controler"
#ifndef bit
#define bit(nr) (1UL << (nr))
#endif
#define mdelay(n) udelay((n)*1000)
/* ***********************************************************
*
* Global varibles and defintions
*
* ***********************************************************
*/
/* configuerable values */
#ifdef BSPETH_RX_QUEUE_MULTI_DESC
#define BSPETH_HW_DESC_DEPTH 72
#endif
#define ETH_MDIO_FRQDIV 2
/* mdiobus device name, such as platform device name */
#define BSPETH_MDIOBUS_NAME "bspeth_mdiobus"
/* eth device name, such as platform device name */
#define BSPETH_FEMAC_NAME "lotus_femac"
#define MAX_PHY_NAME_LEN 16
#define BSPETH_MAX_QUEUE_DEPTH 64
#ifdef BSPETH_RX_QUEUE_MULTI_DESC
#define BSPETH_HW_RXQ_DEPTH 52 /* uboot */
#else
#define BSPETH_HW_RXQ_DEPTH 1 /* uboot */
#endif
#define BSPETH_HW_TXQ_DEPTH 1 /* uboot */
#define BSPETH_MAX_FRAME_SIZE PKTSIZE_ALIGN /* 1536 */
#define BSPETH_TRACE_ETH 2
#define BSPETH_TRACE_MDIO 4
#define BSPETH_TRACE_DRV 7
#define BSPETH_TRACE_LEVEL 8
/* Error number */
#define BSPETH_E_QUEUE (-1)
#define BSPETH_E_BUSY (-2)
#define BSPETH_E_FULL (-3)
#define BSPETH_E_EMPTY (-4)
struct bspeth_frame_desc {
unsigned long frm_addr; /* required by the controler */
unsigned int frm_len : 11; /* required by the controler */
};
#define bspeth_trace_fd(level, fd) bspeth_trace(level, \
#fd "<%p>={ .frm_addr=%08lx, .frm_len=%d}", \
&(fd), (fd).frm_addr, (fd).frm_len)
/* port */
#define UP_PORT 0
#define DOWN_PORT 1
#define MAX_PORT 2
enum if_mode {
INTERFACE_MODE_MII,
INTERFACE_MODE_RMII
};
struct bspeth_netdev_local {
unsigned long iobase_phys; /* physical io addr */
int port : 1; /* 0 => up port, 1 => down port */
#ifdef BSPETH_RX_QUEUE_MULTI_DESC
int desc_hw_offset; /* the offset where we feed hw */
int desc_rec_offset; /* the offset where we receve the package */
struct bspeth_frame_desc *bspeth_desc_head;
#endif
u32 link_stat;
char *mii_name;
unsigned char phy_addr;
enum if_mode phy_intf;
/* mdio_bus freq-div, 1 for 1/100, 0 for 1/50 */
u32 mdio_frqdiv;
};
/* ***********************************************************
*
* 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))
u32 bspeth_readl(struct bspeth_netdev_local *ld, u32 ofs);
void bspeth_writel(struct bspeth_netdev_local *ld, u32 v, u32 ofs);
u32 bspeth_readl_bits(struct bspeth_netdev_local *ld, u32 ofs, u32 bits_desc);
void bspeth_writel_bits(struct bspeth_netdev_local *ld, u32 v, u32 ofs, u32 bits_desc);
void bspeth_trace(int level, const char *fmt, ...);
void bspeth_error(const char *fmt, ...);
void bspeth_assert(bool cond);
#define local_lock_init(ld)
#define local_lock_exit(ld)
#define local_lock(ld)
#define local_unlock(ld)
#define ud_reg_name(name) ((ld->port == UP_PORT) ? U_##name : D_##name)
#define ud_bit_name(name) ((ld->port == UP_PORT) ? name##_U : name##_D)
#endif
@@ -0,0 +1,172 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define BSPETH_FEMAC
#include "bspeth.h"
#include "ctrl.h"
static inline u32 _bspeth_irq_enable(struct bspeth_netdev_local *ld, u32 irqs)
{
u32 old = bspeth_readl(ld, GLB_RW_IRQ_ENA);
bspeth_writel(ld, old | irqs, GLB_RW_IRQ_ENA);
return old;
}
static inline u32 _bspeth_irq_disable(struct bspeth_netdev_local *ld, u32 irqs)
{
u32 old = bspeth_readl(ld, GLB_RW_IRQ_ENA);
bspeth_writel(ld, old & (~irqs), GLB_RW_IRQ_ENA);
return old;
}
static inline u32 _bspeth_read_irqstatus(struct bspeth_netdev_local *ld)
{
u32 status;
status = bspeth_readl(ld, GLB_RO_IRQ_STAT);
return status;
}
u32 bspeth_irq_enable(struct bspeth_netdev_local *ld, u32 irqs)
{
u32 old;
local_lock(ld);
old = _bspeth_irq_enable(ld, irqs);
local_unlock(ld);
return old;
}
u32 bspeth_irq_disable(struct bspeth_netdev_local *ld, u32 irqs)
{
u32 old;
local_lock(ld);
old = _bspeth_irq_disable(ld, irqs);
local_unlock(ld);
return old;
}
u32 bspeth_read_irqstatus(struct bspeth_netdev_local *ld)
{
u32 status;
local_lock(ld);
status = _bspeth_read_irqstatus(ld);
local_unlock(ld);
return status;
}
u32 bspeth_read_raw_irqstatus(struct bspeth_netdev_local *ld)
{
u32 status;
local_lock(ld);
status = bspeth_readl(ld, GLB_RO_IRQ_STAT);
local_unlock(ld);
return status;
}
u32 bspeth_clear_irqstatus(struct bspeth_netdev_local *ld, u32 irqs)
{
u32 status;
local_lock(ld);
bspeth_writel(ld, irqs, GLB_RW_IRQ_RAW);
status = _bspeth_read_irqstatus(ld);
local_unlock(ld);
return status;
}
u32 bspeth_set_endian_mode(struct bspeth_netdev_local *ld, u32 mode)
{
u32 old;
local_lock(ld);
old = bspeth_readl_bits(ld, GLB_ENDIAN_MOD, BITS_ENDIAN);
bspeth_writel_bits(ld, mode, GLB_ENDIAN_MOD, BITS_ENDIAN);
local_unlock(ld);
return old;
}
void hw_xmitq_setfd(struct bspeth_netdev_local *ld, struct bspeth_frame_desc fd)
{
bspeth_writel(ld, fd.frm_addr, ud_reg_name(GLB_EQ_ADDR));
bspeth_writel_bits(ld, fd.frm_len, ud_reg_name(GLB_EQFRM_LEN), BITS_TXINQ_LEN);
}
u32 bspeth_readl(struct bspeth_netdev_local *ld, u32 ofs)
{
u32 reg = _readl((uintptr_t)(ld->iobase_phys + ofs));
bspeth_trace(BSPETH_TRACE_ETH, "_readl(0x%08X) = 0x%08X",
(u32)(ld->iobase_phys + ofs), reg);
return reg;
}
void bspeth_writel(struct bspeth_netdev_local *ld, u32 v, u32 ofs)
{
_writel(v, (uintptr_t)(ld->iobase_phys + ofs));
bspeth_trace(BSPETH_TRACE_ETH, "_writel(0x%08X) = 0x%08X",
(u32)(ld->iobase_phys + ofs), v);
}
u32 bspeth_readl_bits(struct bspeth_netdev_local *ld, u32 ofs, u32 bits_desc)
{
u32 _bits_desc = bits_desc;
u32 _shift = _bits_desc >> 16; /* shift 16 bit */
u32 _mask = ((1 << (_bits_desc & 0x1F)) - 1) << _shift;
u32 reg = (bspeth_readl(ld, ofs) & _mask) >> _shift;
return reg;
}
void bspeth_writel_bits(struct bspeth_netdev_local *ld, u32 v, u32 ofs, u32 bits_desc)
{
u32 _bits_desc = bits_desc;
u32 _shift = _bits_desc >> 16; /* shift 16 bit */
u32 _reg = bspeth_readl(ld, ofs);
u32 _mask = ((1 << (_bits_desc & 0x1F)) - 1) << _shift;
bspeth_writel(ld, (_reg & (~_mask)) | ((v << _shift) & _mask), ofs);
}
void bspeth_trace(int level, const char *fmt, ...)
{
if (level >= BSPETH_TRACE_LEVEL) {
va_list args;
va_start(args, fmt);
printf("bspeth_trace:");
printf(fmt, args);
printf("\n");
va_end(args);
}
}
void bspeth_error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
printf("bspeth:");
printf(fmt, args);
printf("\n");
va_end(args);
}
void bspeth_assert(bool cond)
{
if (!cond)
printf("Assert:bspeth:%s:%d\n", __FILE__, __LINE__);
}
@@ -0,0 +1,148 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __BSPETH_CTRL_H__
#define __BSPETH_CTRL_H__
#include "bspeth.h"
#ifdef BSPETH_FEMAC
/* ENDIAN */
#define GLB_ENDIAN_MOD 0x1318
#define BITS_ENDIAN mk_bits(0, 2)
#define BSPETH_BIG_ENDIAN 0
#define BSPETH_LITTLE_ENDIAN 3
/* IRQs */
#define GLB_RO_IRQ_STAT 0x1330
#define GLB_RW_IRQ_ENA 0x1334
#define GLB_RW_IRQ_RAW 0x1338
/* IRQs mask bits */
#define BITS_IRQS_U mk_bits(0, 8)
#define BITS_VLAN_IRQS mk_bits(11, 1)
#define BITS_MDIO_IRQS mk_bits(13, 2)
#define BITS_IRQS_ENA_D mk_bits(17, 1)
#define BITS_IRQS_ENA_U mk_bits(18, 1)
#define BITS_IRQS_ENA_ALLPORT mk_bits(19, 1)
#define BITS_IRQS_D mk_bits(20, 8)
#define BITS_IRQS_MASK_U (0xFF)
#define BITS_IRQS_MASK_D (0xFF << 20)
/* IRQs bit name */
#define BSPETH_INT_RX_RDY_U bit(0)
#define BSPETH_INT_RX_RDY_D bit(20)
#define BSPETH_INT_TX_FIN_U bit(1)
#define BSPETH_INT_TX_FIN_D bit(21)
#define BSPETH_INT_LINK_CH_U bit(2)
#define BSPETH_INT_LINK_CH_D bit(22)
#define BSPETH_INT_SPEED_CH_U bit(3)
#define BSPETH_INT_SPEED_CH_D bit(23)
#define BSPETH_INT_DUPLEX_CH_U bit(4)
#define BSPETH_INT_DUPLEX_CH_D bit(24)
#define BSPETH_INT_STATE_CH_U bit(5)
#define BSPETH_INT_STATE_CH_D bit(25)
#define BSPETH_INT_TXQUE_RDY_U bit(6)
#define BSPETH_INT_TXQUE_RDY_D bit(26)
#define BSPETH_INT_MULTI_RXRDY_U bit(7)
#define BSPETH_INT_MULTI_RXRDY_D bit(27)
#define BSPETH_INT_MDIO_FINISH bit(12)
#define BSPETH_INT_UNKNOW_VLANID bit(13)
#define BSPETH_INT_UNKNOW_VLANM bit(14)
/* Tx/Rx Queue depth */
#define U_GLB_QLEN_SET 0x0344
#define D_GLB_QLEN_SET 0x2344
#define BITS_TXQ_DEP mk_bits(0, 6)
#define BITS_RXQ_DEP mk_bits(8, 6)
/* Rx (read only) Queue-ID and LEN */
#define U_GLB_RO_IQFRM_DES 0x0354
#define D_GLB_RO_IQFRM_DES 0x2354
/* bits of UD_GLB_RO_IQFRM_DES */
#define BITS_RXPKG_LEN mk_bits(0, 11)
#define BITS_RXPKG_ID mk_bits(12, 6)
#define BITS_FRM_VLAN_VID mk_bits(18, 1)
#define BITS_FD_VID_VID mk_bits(19, 1)
#define BITS_FD_VLANID mk_bits(20, 12)
/* Rx ADDR */
#define U_GLB_IQ_ADDR 0x0358
#define D_GLB_IQ_ADDR 0x2358
/* Tx ADDR and LEN */
#define U_GLB_EQ_ADDR 0x0360
#define D_GLB_EQ_ADDR 0x2360
#define U_GLB_EQFRM_LEN 0x0364
#define D_GLB_EQFRM_LEN 0x2364
/* bits of UD_GLB_EQFRM_LEN */
#define BITS_TXINQ_LEN mk_bits(0, 11)
/* Rx/Tx Queue ID */
#define U_GLB_RO_QUEUE_ID 0x0368
#define D_GLB_RO_QUEUE_ID 0x2368
/* bits of UD_GLB_RO_QUEUE_ID */
#define BITS_TXOUTQ_ID mk_bits(0, 6)
#define BITS_TXINQ_ID mk_bits(8, 6)
#define BITS_RXINQ_ID mk_bits(16, 6)
/* Rx/Tx Queue staus */
#define U_GLB_RO_QUEUE_STAT 0x036C
#define D_GLB_RO_QUEUE_STAT 0x236C
/* bits of UD_GLB_RO_QUEUE_STAT */
/* check this bit to see if we can add a Tx package */
#define BITS_XMITQ_RDY mk_bits(24, 1)
/* check this bit to see if we can add a Rx addr */
#define BITS_RECVQ_RDY mk_bits(25, 1)
/* counts in queue, include currently sending */
#define BITS_XMITQ_CNT_INUSE mk_bits(0, 6)
/* counts in queue, include currently receving */
#define BITS_RECVQ_CNT_RXOK mk_bits(8, 6)
#define is_recv_packet(ld) (bspeth_readl(ld, GLB_RW_IRQ_RAW) & (ud_bit_name(BSPETH_INT_RX_RDY)))
#define is_recv_packet_rx(ld) ((bspeth_readl(ld, ud_reg_name(GLB_RO_QUEUE_STAT)) >> 8) & 0x3F)
#define hw_set_rxpkg_finish(ld) bspeth_writel(ld, ud_bit_name(BSPETH_INT_RX_RDY), GLB_RW_IRQ_RAW)
// //////////////////////////////////////////////////////////////////////////////////////////
#define hw_get_rxpkg_id(ld) bspeth_readl_bits(ld, ud_reg_name(GLB_RO_IQFRM_DES), BITS_RXPKG_ID)
#define hw_get_rxpkg_len(ld) bspeth_readl_bits(ld, ud_reg_name(GLB_RO_IQFRM_DES), BITS_RXPKG_LEN)
#define hw_get_txqid(ld) bspeth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_ID), BITS_TXINQ_ID)
#define hw_get_rxqid(ld) bspeth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_ID), BITS_RXINQ_ID)
#define hw_xmitq_cnt_inuse(ld) bspeth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT), BITS_XMITQ_CNT_INUSE)
#define hw_recvq_cnt_rxok(ld) bspeth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT), BITS_RECVQ_CNT_RXOK)
#define hw_recvq_setfd(ld, fd) bspeth_writel(ld, (fd).frm_addr, ud_reg_name(GLB_IQ_ADDR))
#endif
/* for each bits, set '1' enable the intterrupt, and '0' takes no effects */
/* return last irq_enable status */
u32 bspeth_irq_enable(struct bspeth_netdev_local *ld, u32 irqs);
u32 bspeth_irq_disable(struct bspeth_netdev_local *ld, u32 irqs);
/* return irqstatus */
u32 bspeth_read_irqstatus(struct bspeth_netdev_local *ld);
u32 bspeth_read_raw_irqstatus(struct bspeth_netdev_local *ld);
/* return irqstatus after clean */
u32 bspeth_clear_irqstatus(struct bspeth_netdev_local *ld, u32 irqs);
u32 bspeth_set_endian_mode(struct bspeth_netdev_local *ld, u32 mode);
void hw_xmitq_setfd(struct bspeth_netdev_local *ld, struct bspeth_frame_desc fd);
/* Tx/Rx queue operation */
int bspeth_set_hwq_depth(struct bspeth_netdev_local *ld);
int bspeth_get_hwq_xmit_depth(struct bspeth_netdev_local *ld);
int bspeth_get_hwq_recv_depth(struct bspeth_netdev_local *ld);
#define bspeth_invalid_txqfd_addr(addr) ((addr) & 0x3)
#define bspeth_invalid_rxqfd_addr(addr) ((addr) & 0x3)
#define bspeth_invalid_rxpkg_len(len) (!((len) >= 42 && (len) <= BSPETH_MAX_FRAME_SIZE))
#endif
@@ -0,0 +1,65 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define BSPETH_FEMAC
#include <config.h>
#include "bspeth.h"
#include "mac.h"
#include "ctrl.h"
#include "glb.h"
int bspeth_glb_preinit_dummy(struct bspeth_netdev_local *ld)
{
local_lock_init(ld);
/*
* bspeth_glb_preinit_dummy
* HW MAX DEFAULT RX-PKT-LEN [42,1518]
* HW MAC FILTER TABLE DISABLE
*/
/* soft reset */
bspeth_writel_bits(ld, 1, GLB_SOFT_RESET, BITS_ETH_SOFT_RESET);
mdelay(1);
bspeth_writel_bits(ld, 0, GLB_SOFT_RESET, BITS_ETH_SOFT_RESET);
bspeth_set_endian_mode(ld, BSPETH_LITTLE_ENDIAN);
bspeth_set_linkstat(ld, 0);
bspeth_set_negmode(ld, BSPETH_NEGMODE_CPUSET);
/* RMII mode */
bspeth_set_mii_mode(ld, ud_bit_name(BSPETH_MII_RMII_MODE));
bspeth_writel_bits(ld, ~0, GLB_RW_IRQ_ENA, ud_bit_name(BITS_IRQS));
bspeth_writel_bits(ld, ~0, GLB_RW_IRQ_ENA, ud_bit_name(BITS_IRQS_ENA));
bspeth_writel_bits(ld, ~0, GLB_RW_IRQ_ENA, BITS_IRQS_ENA_ALLPORT);
bspeth_irq_disable(ld, ~0);
/* init */
bspeth_writel(ld, 0, GLB_FWCTRL);
bspeth_writel(ld, 0, GLB_MACTCTRL);
/* disable vlan func */
bspeth_writel_bits(ld, 0, GLB_FWCTRL, BITS_VLAN_ENABLE);
/* enable UpEther<->CPU */
bspeth_writel_bits(ld, 1, GLB_FWCTRL, BITS_FW2CPU_ENA_UP);
bspeth_writel_bits(ld, 0, GLB_FWCTRL, BITS_FWALL2CPU_UP);
bspeth_writel_bits(ld, 0, GLB_MACTCTRL, BITS_BROAD2CPU_UP);
bspeth_writel_bits(ld, 1, GLB_MACTCTRL, BITS_MACT_ENA_UP);
/* enable DownEther<->CPU and UpEther<->CPU */
bspeth_writel_bits(ld, 1, GLB_FWCTRL, BITS_FW2CPU_ENA_DOWN);
bspeth_writel_bits(ld, 0, GLB_FWCTRL, BITS_FWALL2CPU_DOWN);
bspeth_writel_bits(ld, 0, GLB_MACTCTRL, BITS_BROAD2CPU_DOWN);
bspeth_writel_bits(ld, 1, GLB_MACTCTRL, BITS_MACT_ENA_DOWN);
bspeth_set_mac_leadcode_cnt_limit(ld, 0);
return 0;
}
@@ -0,0 +1,40 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __BSPETH_GLB_H__
#define __BSPETH_GLB_H__
#include "bspeth.h"
#define GLB_HOSTMAC_L32 0x1300
#define BITS_HOSTMAC_L32 mk_bits(0, 32)
#define GLB_HOSTMAC_H16 0x1304
#define BITS_HOSTMAC_H16 mk_bits(0, 16)
#define GLB_SOFT_RESET 0x1308
#define BITS_ETH_SOFT_RESET mk_bits(0, 1)
#define GLB_FWCTRL 0x1310
#define BITS_VLAN_ENABLE mk_bits(0, 1)
#define BITS_FW2CPU_ENA_UP mk_bits(5, 1)
#define BITS_FWALL2CPU_UP mk_bits(7, 1)
#define BITS_FW2CPU_ENA_DOWN mk_bits(9, 1)
#define BITS_FWALL2CPU_DOWN mk_bits(11, 1)
#define GLB_MACTCTRL 0x1314
#define BITS_BROAD2CPU_UP mk_bits(5, 1)
#define BITS_BROAD2CPU_DOWN mk_bits(13, 1)
#define BITS_MACT_ENA_DOWN mk_bits(15, 1)
#define BITS_MACT_ENA_UP mk_bits(7, 1)
#define GLB_MAC0_L32 0x1400
#define GLB_MAC0_H16 0x1404
#define BITS_MAC0_H16 mk_bits(0, 16)
#define BITS_PKT2CPU_UP mk_bits(21, 1)
#define BITS_PKT2CPU_DOWN mk_bits(19, 1)
int bspeth_glb_preinit_dummy(struct bspeth_netdev_local *ld);
#endif
@@ -0,0 +1,117 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define BSPETH_FEMAC
#include "bspeth.h"
#include "mac.h"
static u32 _set_linkstat(struct bspeth_netdev_local *ld, u32 mode)
{
u32 old;
old = bspeth_readl_bits(ld, ud_reg_name(MAC_PORTSET), BITS_MACSTAT);
bspeth_writel_bits(ld, mode, ud_reg_name(MAC_PORTSET), BITS_MACSTAT);
return old;
}
static u32 _set_negmode(struct bspeth_netdev_local *ld, u32 mode)
{
u32 old;
old = bspeth_readl_bits(ld, ud_reg_name(MAC_PORTSEL), BITS_NEGMODE);
bspeth_writel_bits(ld, mode, ud_reg_name(MAC_PORTSEL), BITS_NEGMODE);
return old;
}
static u32 _get_negmode(struct bspeth_netdev_local *ld)
{
u32 val;
val = bspeth_readl_bits(ld, ud_reg_name(MAC_PORTSEL), BITS_NEGMODE);
return val;
}
void bspeth_set_linkstat(struct bspeth_netdev_local *ld, u32 mode)
{
local_lock(ld);
(void)_set_linkstat(ld, mode);
local_unlock(ld);
}
u32 bspeth_get_linkstat(struct bspeth_netdev_local *ld)
{
u32 val;
local_lock(ld);
val = bspeth_readl_bits(ld, ud_reg_name(MAC_RO_STAT), BITS_MACSTAT);
local_unlock(ld);
return val;
}
void bspeth_set_mac_leadcode_cnt_limit(struct bspeth_netdev_local *ld, u32 cnt)
{
local_lock(ld);
(void)bspeth_readl_bits(ld, ud_reg_name(MAC_TX_IPGCTRL),
BITS_PRE_CNT_LIMIT);
bspeth_writel_bits(ld, cnt, ud_reg_name(MAC_TX_IPGCTRL),
BITS_PRE_CNT_LIMIT);
local_unlock(ld);
}
void bspeth_set_mac_trans_interval_bits(struct bspeth_netdev_local *ld, u32 nbits)
{
u32 linkstat, negmode;
local_lock(ld);
negmode = _set_negmode(ld, BSPETH_NEGMODE_CPUSET);
linkstat = _set_linkstat(ld, 0);
mdelay(1);
(void)bspeth_readl_bits(ld, ud_reg_name(MAC_TX_IPGCTRL), BITS_IPG);
bspeth_writel_bits(ld, nbits, ud_reg_name(MAC_TX_IPGCTRL), BITS_IPG);
udelay(100); /* delay 100us */
_set_negmode(ld, negmode);
_set_linkstat(ld, linkstat);
local_unlock(ld);
}
void bspeth_set_mac_fc_interval(struct bspeth_netdev_local *ld, u32 para)
{
local_lock(ld);
(void)bspeth_readl_bits(ld, ud_reg_name(MAC_TX_IPGCTRL), BITS_FC_INTER);
bspeth_writel_bits(ld, para, ud_reg_name(MAC_TX_IPGCTRL), BITS_FC_INTER);
local_unlock(ld);
}
void bspeth_set_negmode(struct bspeth_netdev_local *ld, u32 mode)
{
local_lock(ld);
_set_negmode(ld, mode);
local_unlock(ld);
}
u32 bspeth_get_negmode(struct bspeth_netdev_local *ld)
{
u32 val;
local_lock(ld);
val = _get_negmode(ld);
local_unlock(ld);
return val;
}
void bspeth_set_mii_mode(struct bspeth_netdev_local *ld, u32 mode)
{
local_lock(ld);
(void)bspeth_readl_bits(ld, ud_reg_name(MAC_PORTSEL), BITS_MII_MODE);
bspeth_writel_bits(ld, mode, ud_reg_name(MAC_PORTSEL), BITS_MII_MODE);
local_unlock(ld);
}
@@ -0,0 +1,64 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __BSPETH_MAC_H__
#define __BSPETH_MAC_H__
#include "bspeth.h"
#ifdef BSPETH_FEMAC
#define U_MAC_PORTSEL 0x0200
#define D_MAC_PORTSEL 0x2200
#define U_MAC_RO_STAT 0x0204
#define D_MAC_RO_STAT 0x2204
#define U_MAC_PORTSET 0x0208
#define D_MAC_PORTSET 0x2208
#define U_MAC_STAT_CHANGE 0x020C
#define D_MAC_STAT_CHANGE 0x220C
#define U_MAC_SET 0x0210
#define D_MAC_SET 0x2210
#define U_MAC_RX_IPGCTRL 0x0214
#define D_MAC_RX_IPGCTRL 0x2214
#define U_MAC_TX_IPGCTRL 0x0218
#define D_MAC_TX_IPGCTRL 0x2218
/* bits of UD_MAC_PORTSET and UD_MAC_RO_STAT */
#define BITS_MACSTAT mk_bits(0, 3)
/* bits of U_MAC_PORTSEL and D_MAC_PORTSEL */
#define BITS_NEGMODE mk_bits(0, 1)
#define BITS_MII_MODE mk_bits(1, 1)
/* bits of U_MAC_TX_IPGCTRL and D_MAC_TX_IPGCTRL */
#define BITS_PRE_CNT_LIMIT mk_bits(23, 3)
#define BITS_IPG mk_bits(16, 7)
#define BITS_FC_INTER mk_bits(0, 16)
#endif
#define BSPETH_SPD_100M bit(2)
#define BSPETH_LINKED bit(1)
#define BSPETH_DUP_FULL bit(0)
void bspeth_set_mac_leadcode_cnt_limit(struct bspeth_netdev_local *ld, u32 cnt);
void bspeth_set_mac_trans_interval_bits(struct bspeth_netdev_local *ld, u32 nbits);
void bspeth_set_mac_fc_interval(struct bspeth_netdev_local *ld, u32 para);
void bspeth_set_linkstat(struct bspeth_netdev_local *ld, u32 mode);
u32 bspeth_get_linkstat(struct bspeth_netdev_local *ld);
#define BSPETH_NEGMODE_CPUSET 1
#define BSPETH_NEGMODE_AUTO 0
void bspeth_set_negmode(struct bspeth_netdev_local *ld, u32 mode);
u32 bspeth_get_negmode(struct bspeth_netdev_local *ld);
#define BSPETH_MII_MODE 0
#define BSPETH_RMII_MODE 1
void bspeth_set_mii_mode(struct bspeth_netdev_local *ld, u32 mode);
#endif
@@ -0,0 +1,104 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define BSPETH_FEMAC
#include "bspeth.h"
#include "mdio.h"
/* write mdio registers reset value */
static void mdio_reg_reset(struct bspeth_netdev_local *ld)
{
bspeth_writel(ld, 0x00008000, MDIO_RWCTRL);
bspeth_writel(ld, 0x00000001, U_MDIO_PHYADDR);
bspeth_writel(ld, 0x00000001, D_MDIO_PHYADDR);
bspeth_writel(ld, 0x04631EA9, U_MDIO_ANEG_CTRL);
bspeth_writel(ld, 0x04631EA9, D_MDIO_ANEG_CTRL);
bspeth_writel(ld, 0x00000000, U_MDIO_IRQENA);
bspeth_writel(ld, 0x00000000, D_MDIO_IRQENA);
}
static int wait_mdio_ready(struct bspeth_netdev_local *ld)
{
int timeout_us = 5000;
while (--timeout_us && !test_mdio_ready(ld))
udelay(50); /* delay 50us */
return timeout_us;
}
int bspeth_mdio_read(struct bspeth_netdev_local *ld, int phy_addr, unsigned int regnum)
{
int val = 0;
bspeth_assert((!((unsigned int)phy_addr & (~0x1F))) && (!(regnum & (~0x1F))));
local_lock(ld);
if (!wait_mdio_ready(ld)) {
bspeth_error("mdio busy");
goto error_exit;
}
mdio_start_phyread(ld, (unsigned int)phy_addr, regnum);
if (wait_mdio_ready(ld) != 0) {
val = mdio_get_phyread_val(ld);
} else {
bspeth_error("read timeout");
}
error_exit:
local_unlock(ld);
bspeth_trace(BSPETH_TRACE_MDIO, "phy_addr = %d, regnum = %d, val = 0x%04x", phy_addr,
(int)regnum, val);
return val;
}
int bspeth_mdio_write(struct bspeth_netdev_local *ld, int phy_addr, int regnum, int val)
{
bspeth_assert((!((unsigned int)phy_addr & (~0x1F))) && (!((unsigned int)regnum & (~0x1F))));
bspeth_trace(BSPETH_TRACE_MDIO, "phy_addr = %d, regnum = %d", phy_addr, regnum);
local_lock(ld);
if (!wait_mdio_ready(ld)) {
bspeth_error("mdio busy");
val = -1;
goto error_exit;
}
mdio_phywrite(ld, (unsigned int)phy_addr, (unsigned int)regnum, (unsigned int)val);
error_exit:
local_unlock(ld);
return val;
}
int bspeth_mdio_reset(struct bspeth_netdev_local *ld)
{
mdio_reg_reset(ld);
return 0;
}
int bspeth_mdio_init(struct bspeth_netdev_local *ld)
{
local_lock_init(ld);
bspeth_mdio_reset(ld);
return 0;
}
void bspeth_mdio_exit(struct bspeth_netdev_local *ld)
{
local_lock_exit(ld);
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __BSPETH_MDIO_H__
#define __BSPETH_MDIO_H__
#include "bspeth.h"
#ifdef BSPETH_FEMAC
#define MDIO_RWCTRL 0x1100
#define MDIO_RO_DATA 0x1104
#define U_MDIO_PHYADDR 0x0108
#define D_MDIO_PHYADDR 0x2108
#define U_MDIO_RO_STAT 0x010C
#define D_MDIO_RO_STAT 0x210C
#define U_MDIO_ANEG_CTRL 0x0110
#define D_MDIO_ANEG_CTRL 0x2110
#define U_MDIO_IRQENA 0x0114
#define D_MDIO_IRQENA 0x2114
#define mdio_mk_rwctl(cpu_data_in, finish, rw, phy_exaddr, frq_div, phy_regnum) \
(((cpu_data_in) << 16) | (((finish) & 0x01) << 15) | (((rw) & 0x01) << 13) | \
(((phy_exaddr) & 0x1F) << 8) | (((frq_div) & 0x7) << 5) | ((phy_regnum) & 0x1F))
/* hardware set bit'15 of MDIO_REG(0) if mdio ready */
#define test_mdio_ready(ld) (bspeth_readl(ld, MDIO_RWCTRL) & bit(15))
#define mdio_start_phyread(ld, phy_addr, regnum) \
bspeth_writel(ld, mdio_mk_rwctl(0, 0, 0, phy_addr, (ld)->mdio_frqdiv, regnum), MDIO_RWCTRL)
#define mdio_get_phyread_val(ld) (bspeth_readl(ld, MDIO_RO_DATA) & 0xFFFF)
#define mdio_phywrite(ld, phy_addr, regnum, val) \
bspeth_writel(ld, mdio_mk_rwctl(val, 0, 1, phy_addr, (ld)->mdio_frqdiv, regnum), MDIO_RWCTRL)
#endif
/* APIs */
int bspeth_mdio_read(struct bspeth_netdev_local *ld, int phy_addr, unsigned int regnum);
int bspeth_mdio_write(struct bspeth_netdev_local *ld, int phy_addr, int regnum, int val);
int bspeth_mdio_reset(struct bspeth_netdev_local *ld);
int bspeth_mdio_init(struct bspeth_netdev_local *ld);
void bspeth_mdio_exit(struct bspeth_netdev_local *ld);
#endif
@@ -0,0 +1,152 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include "bspeth.h"
#include "mdio.h"
#include "mii_drv.h"
#include <config.h>
/* MDIO Bus Interface */
static int bspeth_mdiobus_read(struct mii_dev *bus, int addr, int devad, int reg)
{
struct bspeth_netdev_local *ld = (struct bspeth_netdev_local *)bus->priv;
return bspeth_mdio_read(ld, addr, reg);
}
static int bspeth_mdiobus_write(struct mii_dev *bus, int addr, int devad,
int reg, u16 value)
{
struct bspeth_netdev_local *ld = (struct bspeth_netdev_local *)bus->priv;
bspeth_mdio_write(ld, addr, reg, value);
return 0;
}
#define PHY_ID_KSZ8051 0x00221550
#define PHY_ID_KSZ8081 0x00221560
#define PHY_ID_MASK 0xFFFFFFF0
static bool get_fephy_id(const char *devname, unsigned char phyaddr, u32 *phy_id)
{
u16 id1 = 0;
u16 id2 = 0;
if (miiphy_read(devname, phyaddr, MII_PHYSID1, &id1)) {
printf("%s,%d:PHY_PHYIDR1 read failed!\n", __func__, __LINE__);
return false;
}
if (miiphy_read(devname, phyaddr, MII_PHYSID2, &id2)) {
printf("%s,%d:PHY_PHYIDR2 read failed!\n", __func__, __LINE__);
return false;
}
*phy_id = (id1 & 0xffff) << 16; /* high 16 bit */
*phy_id |= (id2 & 0xffff);
/* If the phy_id is all Fs, there is no device there */
if (*phy_id == 0xffffffff || *phy_id == 0 || *phy_id == 0xFFFF || *phy_id == 0xFFFF0000) {
return false;
}
return true;
}
bool phy_detected(const char *devname, unsigned char phyaddr)
{
u32 phy_id = 0;
if (!get_fephy_id(devname, phyaddr, &phy_id)) return false;
/* run this at RMII mode */
if (BSPETH_MII_RMII_MODE_U == 1) {
/* PHY-KSZ8051RNL */
if ((phy_id & PHY_ID_MASK) == PHY_ID_KSZ8051) {
unsigned short reg = 0;
if (miiphy_read(devname, phyaddr, 0x1F, &reg)) {
printf("PHY 0x1F read failed\n");
return false;
}
reg |= bit(7); /* bit7:set phy RMII 50MHz clk; */
if (miiphy_write(devname, phyaddr, 0x1F, reg)) {
printf("PHY 0x1F write failed\n");
return false;
}
if (miiphy_read(devname, phyaddr, 0x16, &reg)) {
printf("PHY 0x16 read failed\n");
return false;
}
reg |= bit(1); /* set phy RMII override; */
if (miiphy_write(devname, phyaddr, 0x16, reg)) {
printf("PHY 0x16 write failed\n");
return false;
}
}
/* PHY-KSZ8081 */
if ((phy_id & PHY_ID_MASK) == PHY_ID_KSZ8081) {
unsigned short val = 0;
if (miiphy_read(devname, phyaddr, 0x1F, &val) != 0) {
printf("PHY 0x1F read failed\n");
return false;
};
val |= bit(7); /* bit7:set phy RMII 50MHz clk; */
if (miiphy_write(devname, phyaddr, 0x1F, val) != 0) {
printf("PHY 0x1F write failed\n");
return false;
}
}
}
return true;
}
static int g_mdio_registered;
int bspeth_mdiobus_driver_init(struct bspeth_netdev_local *ld)
{
memset(ld->mii_name, 0, MAX_PHY_NAME_LEN);
snprintf(ld->mii_name, MAX_PHY_NAME_LEN, "mii_bspeth");
ld->mdio_frqdiv = ETH_MDIO_FRQDIV;
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
if (!g_mdio_registered) {
struct mii_dev *bus = mdio_alloc();
if (!bus) {
printf("Failed to allocate MDIO bus\n");
return -ENOMEM;
}
bus->priv = ld;
bus->read = bspeth_mdiobus_read;
bus->write = bspeth_mdiobus_write;
snprintf(bus->name, sizeof(bus->name), ld->mii_name);
bspeth_mdio_init(ld);
if (mdio_register(bus)) {
mdio_free(bus);
return -1;
}
miiphy_set_current_dev(ld->mii_name);
g_mdio_registered = 1;
}
#endif
return 0;
}
void bspeth_mdiobus_driver_exit(struct bspeth_netdev_local *ld)
{
/* add this to avoid the first time to use eth will print 'No such device: XXXXX' message. */
if (!miiphy_get_current_dev()) {
return;
}
bspeth_mdio_exit(ld);
}
@@ -0,0 +1,10 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __BSPETH_MII_DRV_H__
#define __BSPETH_MII_DRV_H__
bool phy_detected(const char *devname, unsigned char phyaddr);
#endif
@@ -0,0 +1,536 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#define BSPETH_FEMAC
#include "bspeth.h"
#include "mac.h"
#include "ctrl.h"
#include "glb.h"
#include "sys.h"
#include "mii_drv.h"
#include <config.h>
#include <miiphy.h>
#include <net.h>
#include <cpu_func.h>
/*************************************************************************/
int bspeth_mdiobus_driver_init(struct bspeth_netdev_local *ld);
void bspeth_mdiobus_driver_exit(struct bspeth_netdev_local *ld);
/* Used when trying to connect to a specific phy (mii bus id:phy device id) */
/* refer linux-2.6.23 ./include/linux/phy.h line 76 */
char mdio_bus_name[MAX_PHY_NAME_LEN];
#define MAC_LEN 6
struct bspeth_netdev_local bspeth_devs_priv[MAX_PORT] = {
{
.port = UP_PORT,
.mii_name = mdio_bus_name,
.phy_addr = SFV_PHY_U,
.phy_intf = BSPETH_MII_RMII_MODE_U,
},
{
.port = DOWN_PORT,
.mii_name = mdio_bus_name,
.phy_addr = SFV_PHY_D,
.phy_intf = BSPETH_MII_RMII_MODE_D,
},
};
static int set_mac_address(const char *mac)
{
u32 val;
val = ((u32)mac[0] << 8) | (u32)mac[1]; /* mac 0 [8:15], mac 1 [0:7] */
writel(val, REG_BASE_SF + GLB_HOSTMAC_H16);
/* mac 2 [24:31], mac 3 [16:23], mac 4 [8:15], mac 5 [0:7] */
val = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) | ((u32)mac[4] << 8) | (u32)mac[5];
writel(val, REG_BASE_SF + GLB_HOSTMAC_L32);
return 0;
}
#ifdef BSPETH_RX_QUEUE_MULTI_DESC
static int bspeth_init_hw_desc_queue(struct bspeth_netdev_local *ld)
{
struct bspeth_frame_desc *queue_phy_addr = NULL;
int i;
const int size = BSPETH_HW_DESC_DEPTH * sizeof(struct bspeth_frame_desc);
/* init rx fq */
queue_phy_addr = (struct bspeth_frame_desc *)malloc(size);
if (queue_phy_addr == NULL) {
printf("alloc rx fq error!\n");
return 1;
}
memset((void *)queue_phy_addr, 0, size);
ld->bspeth_desc_head = queue_phy_addr;
ld->desc_hw_offset = 0;
ld->desc_rec_offset = 0;
for (i = 0; i < BSPETH_HW_DESC_DEPTH; i++) {
queue_phy_addr[i].frm_addr = (unsigned long)memalign(PKTALIGN, PKTSIZE_ALIGN);
queue_phy_addr[i].frm_len = 0;
}
return 0;
}
#endif
#ifdef BSPETH_RX_QUEUE_MULTI_DESC
static int bspeth_destroy_hw_desc_queue(struct bspeth_netdev_local *ld)
{
struct bspeth_frame_desc *queue_phy_addr = ld->bspeth_desc_head;
int i;
if (queue_phy_addr != NULL) {
for (i = 0; i < BSPETH_HW_DESC_DEPTH; i++)
free((void *)queue_phy_addr[i].frm_addr);
free(ld->bspeth_desc_head);
ld->bspeth_desc_head = NULL;
}
ld->desc_hw_offset = 0;
ld->desc_rec_offset = 0;
return 0;
}
#endif
int eth_set_host_mac_address(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
}
set_mac_address((char *)mac);
memcpy(dev->enetaddr, mac, MAC_LEN);
return 0;
}
static void phy_print_status(struct bspeth_netdev_local *ld, unsigned int stat)
{
printf("%s : phy status change : LINK=%s : DUPLEX=%s : SPEED=%s\n",
(ld->port == UP_PORT) ? "eth0" : "eth1",
(stat & BSPETH_LINKED) ? "UP" : "DOWN",
(stat & BSPETH_DUP_FULL) ? "FULL" : "HALF",
(stat & BSPETH_SPD_100M) ? "100M" : "10M");
}
static void bspeth_adjust_link(struct bspeth_netdev_local *ld)
{
u32 stat = 0;
int timeout_us = 1000;
/* this env phy_link_time used to solve the difference phy auto-negotiation time of various phys */
char *timeout = env_get("phy_link_time");
if (timeout != NULL) {
timeout_us = simple_strtol(timeout, 0, 10); /* Base10 */
if (timeout_us < 0)
timeout_us = 1000; /* delay 1000us */
}
retry:
udelay(1);
stat |= miiphy_link(ld->mii_name, ld->phy_addr) ? BSPETH_LINKED : 0;
stat |= miiphy_duplex(ld->mii_name, ld->phy_addr) == FULL ? BSPETH_DUP_FULL : 0;
stat |= miiphy_speed(ld->mii_name, ld->phy_addr) == _100BASET ? BSPETH_SPD_100M : 0;
if (--timeout_us && !(stat & BSPETH_LINKED))
goto retry;
if (stat != ld->link_stat) {
bspeth_set_linkstat(ld, stat);
phy_print_status(ld, stat);
ld->link_stat = stat;
bspeth_set_mii_mode(ld, ld->phy_intf);
}
set_phy_valtage();
}
static int bspeth_net_open(struct bspeth_netdev_local *ld)
{
/* enable sys-ctrl-en and clk-en */
bspeth_sys_startup();
/* setup hardware tx dep */
bspeth_writel_bits(ld, BSPETH_HW_TXQ_DEPTH, ud_reg_name(GLB_QLEN_SET), BITS_TXQ_DEP);
/* setup hardware rx dep */
bspeth_writel_bits(ld, BSPETH_HW_RXQ_DEPTH, ud_reg_name(GLB_QLEN_SET), BITS_RXQ_DEP);
ld->link_stat = 0;
bspeth_adjust_link(ld);
bspeth_irq_enable(ld, ud_bit_name(BSPETH_INT_RX_RDY));
return 0;
}
static int bspeth_net_close(struct bspeth_netdev_local *ld)
{
bspeth_glb_preinit_dummy(ld);
bspeth_sys_allstop();
return 0;
}
static int bspeth_dev_probe_init(struct bspeth_netdev_local *ld)
{
ld->iobase_phys = REG_BASE_SF;
bspeth_glb_preinit_dummy(ld);
#ifdef BSPETH_RX_QUEUE_MULTI_DESC
bspeth_init_hw_desc_queue(ld);
#endif
bspeth_sys_allstop();
return 0;
}
static int bspeth_dev_remove(struct bspeth_netdev_local *ld)
{
#ifdef BSPETH_RX_QUEUE_MULTI_DESC
bspeth_destroy_hw_desc_queue(ld);
#endif
return 0;
}
static void bspeth_get_phy_intf(struct bspeth_netdev_local *ld)
{
char *mdio_intf = NULL;
/* get mdio interface from env.FORMAT: mdio_intf=mii or mdio_intf=rmii */
mdio_intf = env_get("mdio_intf");
if (mdio_intf != NULL) {
if (!strncmp(mdio_intf, "mii", strlen("mii"))) {
ld->phy_intf = INTERFACE_MODE_MII;
} else if (!strncmp(mdio_intf, "rmii", strlen("rmii"))) {
ld->phy_intf = INTERFACE_MODE_RMII;
} else {
printf("Invalid mdio_intf, should be mii or rmii.\n");
ld->phy_intf = INTERFACE_MODE_RMII;
}
}
}
static void bspeth_get_phy_addr(struct bspeth_netdev_local *ld)
{
char *phyaddr = NULL;
char addr_name[MAX_PORT][10] = { "phyaddru", "phyaddrd" }; /* max name size is 10 */
if (ld->port >= MAX_PORT)
return;
/* get phy addr of up port */
phyaddr = env_get(addr_name[ld->port]);
if (phyaddr != NULL) {
unsigned long tmp = simple_strtoul(phyaddr, 0, 10); /* use Base10 */
/* check phyaddr > 0x1f */
if (tmp >= 0x1f) {
printf("Detected env '%s' had been set greater"
"than 0x1f,this may not correct.\n",
addr_name[ld->port]);
return;
}
ld->phy_addr = (unsigned char)tmp;
} else {
#if defined(INNER_PHY)
if (ld->port == UP_PORT) {
#if defined(INNER_PHY_ADDR_U)
ld->phy_addr = INNER_PHY_ADDR_U;
#endif
} else {
#if defined(INNER_PHY_ADDR_D)
ld->phy_addr = INNER_PHY_ADDR_D;
#endif
}
#endif
}
}
static void bspeth_exit(struct bspeth_netdev_local *ld)
{
bspeth_mdiobus_driver_exit(ld);
bspeth_sys_exit();
}
int bspeth_init(struct eth_device *dev, bd_t *bd)
{
struct bspeth_netdev_local *ld = (struct bspeth_netdev_local *)dev->priv;
int ret;
int count = 30;
bspeth_get_phy_intf(ld);
bspeth_get_phy_addr(ld);
#ifdef INNER_PHY
if (ld->port == UP_PORT)
set_inner_phy_addr(ld->phy_addr);
#endif
printf(OSDRV_MODULE_VERSION_STRING "\n");
set_efuse_unread();
/* sys-func-sel */
bspeth_sys_init();
/* register MDIO bus to uboot */
if (bspeth_mdiobus_driver_init(ld) != 0) {
goto _error_bspeth_init;
}
if (phy_detected(ld->mii_name, ld->phy_addr) == false) {
goto _error_bspeth_init;
}
miiphy_reset(ld->mii_name, ld->phy_addr);
ret = bspeth_dev_probe_init(ld);
if (ret) {
bspeth_error("register Ether netdevice"
" driver failed!");
goto _error_bspeth_init;
}
eth_set_host_mac_address(dev);
while (--count >= 0) {
/* open UpEther net dev */
bspeth_net_open(ld);
if (ld->link_stat & BSPETH_LINKED) {
return 0;
}
}
printf("PHY not link.\n");
_error_bspeth_init:
bspeth_mdiobus_driver_exit(ld);
bspeth_net_close(ld);
return -1;
}
#ifdef BSPETH_RX_QUEUE_MULTI_DESC
static int bspeth_recv(struct eth_device *dev)
{
struct bspeth_netdev_local *ld = (struct bspeth_netdev_local *)dev->priv;
int recvq_ready, hw_offset, rec_offset;
int timeout_us = 10000;
struct bspeth_frame_desc *fd;
struct bspeth_frame_desc receive_fd;
fd = ld->bspeth_desc_head;
hw_offset = ld->desc_hw_offset;
rec_offset = ld->desc_rec_offset;
/* check this we can add a Rx addr */
recvq_ready = bspeth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT), BITS_RECVQ_RDY);
if (!recvq_ready)
bspeth_trace(BSPETH_TRACE_DRV, "hw can't add a rx addr.");
while (recvq_ready &&
((hw_offset + 1) % BSPETH_HW_DESC_DEPTH != rec_offset)) {
receive_fd = fd[hw_offset];
invalidate_dcache_range(receive_fd.frm_addr,
ALIGN(receive_fd.frm_addr + PKTSIZE_ALIGN, ARCH_DMA_MINALIGN));
hw_recvq_setfd(ld, receive_fd);
hw_offset = (hw_offset + 1) % BSPETH_HW_DESC_DEPTH;
recvq_ready =
bspeth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT),
BITS_RECVQ_RDY);
}
ld->desc_hw_offset = hw_offset;
/* receive packed, loop in NetLoop */
while (--timeout_us && !is_recv_packet_rx(ld))
udelay(1);
if (is_recv_packet_rx(ld)) {
receive_fd = fd[rec_offset];
receive_fd.frm_len = hw_get_rxpkg_len(ld);
hw_set_rxpkg_finish(ld);
rec_offset = (rec_offset + 1) % BSPETH_HW_DESC_DEPTH;
ld->desc_rec_offset = rec_offset;
if (bspeth_invalid_rxpkg_len(receive_fd.frm_len)) {
bspeth_error("frm_len invalid (%u)", receive_fd.frm_len);
goto _error_exit;
}
invalidate_dcache_range(receive_fd.frm_addr,
ALIGN(receive_fd.frm_addr + receive_fd.frm_len, ARCH_DMA_MINALIGN));
memcpy((void *)net_rx_packets[0], (void *)receive_fd.frm_addr,
receive_fd.frm_len);
/* Pass the packet up to the protocol layers. */
net_process_received_packet(net_rx_packets[0], receive_fd.frm_len);
return 0;
} else {
bspeth_trace(BSPETH_TRACE_DRV, "hw rx timeout.");
}
_error_exit:
return -1;
}
#else
static int bspeth_recv(struct eth_device *dev)
{
struct bspeth_netdev_local *ld = (struct bspeth_netdev_local *)dev->priv;
int recvq_ready;
int timeout_us = 10000;
struct bspeth_frame_desc fd = { 0 };
/* check this we can add a Rx addr */
recvq_ready = bspeth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT), BITS_RECVQ_RDY);
if (!recvq_ready)
bspeth_trace(BSPETH_TRACE_DRV, "hw can't add a rx addr.");
/* enable rx int */
bspeth_irq_enable(ld, ud_bit_name(BSPETH_INT_RX_RDY));
/* fill rx hwq fd */
fd.frm_addr = (uintptr_t)net_rx_packets[0];
fd.frm_len = 0;
/* recv data will be put into DDR , in case of get the cache data, mush be invalid Dcache */
invalidate_dcache_range(fd.frm_addr, ALIGN(fd.frm_addr + PKTSIZE_ALIGN, ARCH_DMA_MINALIGN));
hw_recvq_setfd(ld, fd);
/* receive packed, loop in NetLoop */
while (--timeout_us && !is_recv_packet(ld))
udelay(1);
if (is_recv_packet(ld)) {
fd.frm_len = hw_get_rxpkg_len(ld);
hw_set_rxpkg_finish(ld);
if (bspeth_invalid_rxpkg_len(fd.frm_len)) {
bspeth_error("frm_len invalid (%u)", fd.frm_len);
goto _error_exit;
}
invalidate_dcache_range(fd.frm_addr,
ALIGN(fd.frm_addr + fd.frm_len, ARCH_DMA_MINALIGN));
/* Pass the packet up to the protocol layers. */
net_process_received_packet(net_rx_packets[0], fd.frm_len);
return 0;
} else {
bspeth_trace(BSPETH_TRACE_DRV, "hw rx timeout.");
}
_error_exit:
return -1;
}
#endif
#define ETH_FCS_LEN 4 /* Octets in the FCS */
static int bspeth_send(struct eth_device *dev, void *packet, int length)
{
struct bspeth_netdev_local *ld = (struct bspeth_netdev_local *)dev->priv;
unsigned int ints, xmitq_ready;
unsigned int timeout_us = 3000;
struct bspeth_frame_desc fd;
/* check this we can add a Tx addr */
xmitq_ready = bspeth_readl_bits(ld, ud_reg_name(GLB_RO_QUEUE_STAT), BITS_XMITQ_RDY);
if (!xmitq_ready) {
bspeth_error("hw can't add a tx addr");
goto _error_exit;
}
/* enable tx int */
bspeth_irq_enable(ld, ud_bit_name(BSPETH_INT_TXQUE_RDY));
flush_cache((uintptr_t)packet, ALIGN((unsigned int)length + ETH_FCS_LEN, ARCH_DMA_MINALIGN));
/* fill tx hwq fd */
fd.frm_addr = (uintptr_t)packet;
fd.frm_len = length + ETH_FCS_LEN;
hw_xmitq_setfd(ld, fd);
do {
udelay(1);
ints = bspeth_read_irqstatus(ld);
} while (--timeout_us && !(ints & ud_bit_name(BSPETH_INT_TXQUE_RDY)));
bspeth_clear_irqstatus(ld, ints);
if (!timeout_us) {
bspeth_error("hw tx timeout");
goto _error_exit;
}
return 0;
_error_exit:
return -1;
}
static void bspeth_halt(struct eth_device *dev)
{
struct bspeth_netdev_local *ld = (struct bspeth_netdev_local *)dev->priv;
bspeth_net_close(ld);
bspeth_dev_remove(ld);
bspeth_exit(ld);
}
static int bspeth_register_dev(unsigned char port_id)
{
struct eth_device *dev;
dev = malloc(sizeof(*dev));
if (dev == NULL)
return -1;
memset(dev, 0, sizeof(*dev));
dev->iobase = REG_BASE_SF;
dev->init = bspeth_init;
dev->halt = bspeth_halt;
dev->send = bspeth_send;
dev->recv = bspeth_recv;
dev->priv = &bspeth_devs_priv[port_id];
bspeth_devs_priv[port_id].iobase_phys = REG_BASE_SF;
snprintf(dev->name, sizeof(dev->name) - 1, "eth%d", port_id);
eth_register(dev);
return 0;
}
int bspeth_initialize(bd_t *bis)
{
int ret;
ret = bspeth_register_dev(UP_PORT);
if (ret)
return ret;
return 0;
}
@@ -0,0 +1,252 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#include <config.h>
#include "bspeth.h"
#include "sys.h"
#define BSPETH_CRG_REG (CRG_REG_BASE + REG_ETH_CRG)
#define ETH_SOFT_RESET bit(0)
#define ETH_CLK_ENABLE bit(1)
#if defined(SFV_RESET_PHY_BY_CRG)
#define ETH_EXTERNAL_PHY_RESET bit(3)
#endif
#define ETH_CORE_CLK_SELECT_54M bit(7)
#if (defined CONFIG_TARGET_XMFALCON)
#define BSPETH_SYSCTL_REG (SYS_CTRL_REG_BASE + MISC_CTRL9)
#define ETH_INTERNAL_PHY_RESET bit(3)
#define ETH_INTERNAL_PHY_CLK_EN bit(2)
#elif (defined CONFIG_TARGET_XMORCA)
#define BSPETH_SYSCTL_REG (SYS_CTRL_REG_BASE + MISC_CTRL9)
#define ETH_INTERNAL_PHY_RESET bit(3)
#define ETH_INTERNAL_PHY_CLK_EN bit(2)
#endif
#define BSPETH_CRG_INPHY_CLK_REG BSPETH_CRG_REG
#define BSPETH_CRG_EXTPHY_CLK_REG BSPETH_CRG_REG
#if 0
void set_efuse_unread(void)
{
u32 reg_value;
reg_value = readl(BSPETH_EFUSE_REG);
reg_value |= 0x1;
writel(reg_value, BSPETH_EFUSE_REG);
reg_value = readl(BSPETH_EFUSE_DATA_REG);
reg_value |= 0x1;
writel(reg_value, BSPETH_EFUSE_DATA_REG);
mdelay(300); /* delay 300ms */
reg_value = readl(BSPETH_EFUSE_REG);
reg_value &= ~0x1;
writel(reg_value, BSPETH_EFUSE_REG);
}
#else
void set_efuse_unread(void)
{
}
#endif
#ifdef INNER_PHY
void set_inner_phy_addr(u32 phy_addr)
{
u32 reg_value;
reg_value = readl(MISC_REG_BASE + MISC_CTRL9);
reg_value &= ~0x1f;
phy_addr &= 0x1f;
reg_value |= phy_addr;
writel(reg_value, (MISC_REG_BASE + MISC_CTRL9));
}
#else
void set_inner_phy_addr(u32 phyaddr)
{
}
#endif
void revise_led_shine(void)
{
}
void set_phy_valtage(void)
{
}
static void bspeth_reset(int rst)
{
u32 val;
val = _readl(BSPETH_CRG_REG);
if (rst) {
val |= ETH_SOFT_RESET;
} else {
val &= ~ETH_SOFT_RESET;
}
_writel(val, BSPETH_CRG_REG);
udelay(100); /* delay 100us */
}
static inline void bspeth_clk_ena(void)
{
u32 val = _readl(BSPETH_CRG_REG);
val |= (ETH_CORE_CLK_SELECT_54M | ETH_CLK_ENABLE);
_writel(val, BSPETH_CRG_REG);
}
static inline void bspeth_clk_dis(void)
{
u32 val = _readl(BSPETH_CRG_REG);
val &= ~ETH_CLK_ENABLE;
_writel(val, BSPETH_CRG_REG);
}
#if defined(INNER_PHY)
static void bspeth_fephy_trim(void)
{
/* To simplify internal FEPHY trim process,
* we just delay 300ms to wait FEPHY auto-trim completed.
* Not read trim data from EFUSE register.
*/
mdelay(350); /* delay 350ms */
}
#endif
static void bspeth_reset_internal_phy(void)
{
#ifdef INNER_PHY
u32 rst;
/* disable MDCK clock to make sure FEPHY reset success */
bspeth_clk_dis();
rst = readl(BSPETH_CRG_INPHY_CLK_REG);
rst |= ETH_INTERNAL_PHY_CLK_EN;
/* internal FEPHY only support MII mode */
writel(rst, BSPETH_CRG_INPHY_CLK_REG);
udelay(10); /* delay 10us */
rst = _readl(BSPETH_CRG_INPHY_CLK_REG);
rst |= ETH_INTERNAL_PHY_RESET;
_writel(rst, BSPETH_CRG_INPHY_CLK_REG);
/* delay at least 10ms */
mdelay(15); /* delay 15ms */
rst = _readl(BSPETH_CRG_INPHY_CLK_REG);
rst &= ~ETH_INTERNAL_PHY_RESET;
_writel(rst, BSPETH_CRG_INPHY_CLK_REG);
/* delay at least 15ms for MDIO operation */
mdelay(20); /* delay 20ms */
bspeth_clk_ena();
/* delay 5ms after enable MDCK to make sure FEPHY trim safe */
mdelay(5); /* delay 5ms */
bspeth_fephy_trim();
#endif
}
static void bspeth_reset_external_phy_by_crg(void)
{
#if defined(SFV_RESET_PHY_BY_CRG)
u32 v;
/************************************************/
/* reset external phy with default reset pin */
v = readl(BSPETH_CRG_EXTPHY_CLK_REG);
v |= ETH_EXTERNAL_PHY_RESET;
writel(v, BSPETH_CRG_EXTPHY_CLK_REG);
mdelay(50); /* delay 50ms */
/* then, cancel reset, and should delay some time */
v = readl(BSPETH_CRG_EXTPHY_CLK_REG);
v &= ~ETH_EXTERNAL_PHY_RESET;
writel(v, BSPETH_CRG_EXTPHY_CLK_REG);
mdelay(50); /* delay 50ms */
#endif
}
static void bspeth_reset_external_phy_by_gpio(void)
{
#ifdef SFV_RESET_GPIO_EN
unsigned int val;
/* gpiox[x] set to reset, then delay 200ms */
val = __raw_readw(SFV_RESET_GPIO_BASE + SFV_RESET_GPIO_DIR);
val |= (SFV_RESET_GPIO_DIR_OUT << SFV_RESET_GPIO_BIT);
__raw_writew(val, SFV_RESET_GPIO_BASE + SFV_RESET_GPIO_DIR);
__raw_writew(SFV_RESET_GPIO_DATA,
SFV_RESET_GPIO_BASE +
(4 << SFV_RESET_GPIO_BIT)); /* offset addr 4 */
mdelay(200); /* delay 200ms */
/* then,cancel reset,and should delay 200ms */
val = __raw_readw(SFV_RESET_GPIO_BASE + SFV_RESET_GPIO_DIR);
val |= (SFV_RESET_GPIO_DIR_OUT << SFV_RESET_GPIO_BIT);
__raw_writew(val, SFV_RESET_GPIO_BASE + SFV_RESET_GPIO_DIR);
__raw_writew(((!SFV_RESET_GPIO_DATA) << SFV_RESET_GPIO_BIT),
SFV_RESET_GPIO_BASE +
(4 << SFV_RESET_GPIO_BIT)); /* offset addr 4 */
mdelay(20); /* delay 20ms */
#endif
}
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)
{
}
void bspeth_sys_init(void)
{
bspeth_funsel_config();
bspeth_sys_allstop();
bspeth_clk_ena();
bspeth_reset(1);
bspeth_reset(0);
bspeth_phy_reset();
revise_led_shine();
}
void bspeth_sys_exit(void)
{
bspeth_funsel_restore();
bspeth_sys_allstop();
}
@@ -0,0 +1,19 @@
/*
* Copyright (c) LOTUS. All rights reserved.
*/
#ifndef __BSPETH_SYS_H__
#define __BSPETH_SYS_H__
void bspeth_sys_init(void);
void bspeth_sys_exit(void);
void bspeth_set_crg_phy_mode(unsigned char is_rmii_mode);
void set_inner_phy_addr(u32 phyaddr);
void set_efuse_unread(void);
void bspeth_sys_startup(void);
void bspeth_sys_allstop(void);
void set_phy_valtage(void);
#endif