GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -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, ®)) {
|
||||
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, ®)) {
|
||||
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
|
||||
Reference in New Issue
Block a user