303 lines
6.7 KiB
C
303 lines
6.7 KiB
C
/*
|
|
* pegasus.c- Sigmastar
|
|
*
|
|
* Copyright (C) 2018 Sigmastar Technology Corp.
|
|
*
|
|
* Author: jiang.ann <jiang.ann@sigmastar.com.tw>
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*/
|
|
|
|
#include <common.h>
|
|
|
|
#include <net.h>
|
|
#include "usb.h"
|
|
#include "usb_lan.h"
|
|
|
|
enum pegasus_registers {
|
|
EthCtrl0 = 0,
|
|
EthCtrl1 = 1,
|
|
EthCtrl2 = 2,
|
|
EthID = 0x10,
|
|
Reg1d = 0x1d,
|
|
EpromOffset = 0x20,
|
|
EpromData = 0x21, /* 0x21 low, 0x22 high byte */
|
|
EpromCtrl = 0x23,
|
|
PhyAddr = 0x25,
|
|
PhyData = 0x26, /* 0x26 low, 0x27 high byte */
|
|
PhyCtrl = 0x28,
|
|
UsbStst = 0x2a,
|
|
EthTxStat0 = 0x2b,
|
|
EthTxStat1 = 0x2c,
|
|
EthRxStat = 0x2d,
|
|
WakeupControl = 0x78,
|
|
Reg7b = 0x7b,
|
|
Gpio0 = 0x7e,
|
|
Gpio1 = 0x7f,
|
|
Reg81 = 0x81,
|
|
};
|
|
|
|
#define PEGASUS_REQT_READ (0xc0)
|
|
#define PEGASUS_REQT_WRITE (0x40)
|
|
#define PEGASUS_REQ_GET_REGS (0xf0)
|
|
#define PEGASUS_REQ_SET_REGS (0xf1)
|
|
|
|
#define DEFAULT_GPIO_RESET (0x24)
|
|
#define DEFAULT_GPIO_SET (0x26)
|
|
|
|
#define PEGASUS_MTU (1536)
|
|
#define REG_TIMEOUT (100)
|
|
|
|
static unsigned char netbuf[PEGASUS_MTU] __attribute__ ((aligned (8)));
|
|
|
|
extern void wait_ms(unsigned long ms);
|
|
extern int usb_bulk_transfer_in(struct usb_device *dev,
|
|
void *data, int len,int *transdata);
|
|
extern int usb_bulk_transfer_out(struct usb_device *dev,
|
|
void *data, int len);
|
|
|
|
/* NIC specific static variables go here */
|
|
static char packet[2096];
|
|
|
|
/**************************************************************************
|
|
Pegasus Operations
|
|
***************************************************************************/
|
|
static int get_registers(struct eth_device *nic, u16 reg, u16 size, void *data)
|
|
{
|
|
return usb_control_msg(nic->udev, usb_rcvctrlpipe(nic->udev, 0),
|
|
PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ,
|
|
0, reg, data, size, 500);
|
|
}
|
|
|
|
static int set_registers(struct eth_device *nic, u16 reg, u16 size, void *data)
|
|
{
|
|
return usb_control_msg(nic->udev, usb_sndctrlpipe(nic->udev, 0),
|
|
PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE,
|
|
0, reg, data, size, 500);
|
|
}
|
|
|
|
static int set_register(struct eth_device *nic, u16 reg, u8 data)
|
|
{
|
|
return usb_control_msg(nic->udev, usb_sndctrlpipe(nic->udev, 0),
|
|
PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE,
|
|
data, reg, &data, 1, 500);
|
|
}
|
|
|
|
static void disable_net_traffic(struct eth_device *nic)
|
|
{
|
|
u8 tmp = 0;
|
|
|
|
DEBUGFUNC();
|
|
set_registers(nic, EthCtrl0, 2, &tmp);
|
|
}
|
|
|
|
static void pegasus_disable(struct eth_device *nic)
|
|
{
|
|
DEBUGFUNC();
|
|
|
|
netif_stop_queue(nic);
|
|
disable_net_traffic(nic);
|
|
}
|
|
|
|
static inline int
|
|
reset_mac(struct eth_device *nic)
|
|
{
|
|
u8 data = 0x8;
|
|
int i;
|
|
|
|
DEBUGFUNC();
|
|
set_register(nic, EthCtrl1, 0x08);
|
|
for (i = 0; i < REG_TIMEOUT; i++)
|
|
{
|
|
get_registers(nic, EthCtrl1, 1, &data);
|
|
if (~data & 0x08)
|
|
{
|
|
set_register(nic, Gpio1, 0x26);
|
|
set_register(nic, Gpio0, 0x24);
|
|
set_register(nic, Gpio0, DEFAULT_GPIO_SET);
|
|
break;
|
|
}
|
|
}
|
|
if (i == REG_TIMEOUT)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int pegasus_reset(struct eth_device *nic)
|
|
{
|
|
// u8 data = 0;
|
|
|
|
DEBUGFUNC();
|
|
|
|
reset_mac(nic);
|
|
set_register(nic, Reg1d, 0);
|
|
//reset phy
|
|
set_register(nic, Reg7b, 1);
|
|
wait_ms(100);
|
|
//stop reset phy
|
|
set_register(nic, Reg7b, 2);
|
|
return 1;
|
|
}
|
|
|
|
static int enable_net_traffic(struct eth_device *nic)
|
|
{
|
|
u8 data[4];
|
|
|
|
DEBUGFUNC();
|
|
data[0] = 0xc9;
|
|
data[1] = 0;
|
|
data[1] |= 0x20; /* set full duplex */
|
|
data[1] |= 0x10; /* set 100 Mbps */
|
|
//loopback = 0x09, otherwise = 0x01
|
|
data[2] = 0x01;
|
|
|
|
set_registers(nic, EthCtrl0, 3, data);
|
|
return 1;
|
|
}
|
|
|
|
static void set_ethernet_addr(struct eth_device *nic)
|
|
{
|
|
u8 node_id[6];
|
|
|
|
DEBUGFUNC();
|
|
memset(node_id, 0, sizeof(node_id));
|
|
get_registers(nic, EthID, sizeof(node_id), node_id);
|
|
memcpy(nic->enetaddr, node_id, sizeof(node_id));
|
|
|
|
USB_LAN_DBG("net addr:%x-%x-%x-%x-%x-%x\n",nic->enetaddr[0],nic->enetaddr[1],nic->enetaddr[2],nic->enetaddr[3],nic->enetaddr[4],nic->enetaddr[5]);
|
|
}
|
|
|
|
#if USE_DUMP_PACKET
|
|
static void dump_pkt(u8 *pkt, u32 len)
|
|
{
|
|
u32 i = 0;
|
|
|
|
DEBUGFUNC();
|
|
|
|
for (; i< len; i++)
|
|
{
|
|
if (i%0x10 == 0)
|
|
printf("\n%x: ", pkt);
|
|
|
|
if (*pkt < 0x10)
|
|
printf("0%x ", *pkt);
|
|
else
|
|
printf("%x ", *pkt);
|
|
pkt++;
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
|
|
/**************************************************************************
|
|
POLL - Wait for a frame
|
|
***************************************************************************/
|
|
static int
|
|
pegasus_rx(struct eth_device *nic)
|
|
{
|
|
void *usb_buffer;
|
|
int datalen;
|
|
|
|
DEBUGFUNC();
|
|
|
|
usb_buffer=(void*)&netbuf[0];
|
|
if (usb_bulk_transfer_in((nic->udev),usb_buffer, PEGASUS_MTU,&datalen) < 0)
|
|
return -1;
|
|
|
|
memcpy((uchar *)packet,(usb_buffer),datalen);
|
|
//flush read buffer data
|
|
((volatile u32 *)0xA001000)[0];
|
|
#if USE_DUMP_PACKET
|
|
dump_pkt(usb_buffer, length);
|
|
#endif
|
|
|
|
//#ifndef CONFIG_USE_UBOOT2017
|
|
NetReceive((uchar *)packet, datalen);
|
|
//#else
|
|
// net_process_received_packet((uchar *)packet, datalen);
|
|
//#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**************************************************************************
|
|
TRANSMIT - Transmit a frame
|
|
***************************************************************************/
|
|
static int
|
|
pegasus_tx(struct eth_device *nic, volatile void *packet, int length)
|
|
{
|
|
void *usb_buffer;
|
|
|
|
usb_buffer=(void*)&netbuf[0];
|
|
memcpy(usb_buffer+2,(void *)packet,length);
|
|
//@FIXME:add 2 dummy bytes to avoid USB LAN ignore it
|
|
length +=2;
|
|
while (length < 60) //padding to 60 bytes
|
|
{
|
|
*((u8*)usb_buffer+length)=0;
|
|
length++;
|
|
}
|
|
|
|
#if USE_DUMP_PACKET
|
|
dump_pkt(usb_buffer, length);
|
|
#endif
|
|
if (usb_bulk_transfer_out( nic->udev,usb_buffer, length) < 0)
|
|
return -1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
pegasus_open(struct eth_device *nic, bd_t * bis)
|
|
{
|
|
DEBUGFUNC();
|
|
|
|
set_registers(nic, EthID, 6, nic->enetaddr);
|
|
enable_net_traffic(nic);
|
|
return 1;
|
|
}
|
|
|
|
/**************************************************************************
|
|
INIT - set up ethernet interface(s)
|
|
***************************************************************************/
|
|
int pegasus_init(struct eth_device *nic)
|
|
{
|
|
DEBUGFUNC();
|
|
|
|
nic->init = pegasus_open;
|
|
nic->recv = pegasus_rx;
|
|
nic->send = pegasus_tx;
|
|
nic->halt = pegasus_disable;
|
|
|
|
set_register(nic, EpromCtrl, 0);
|
|
set_register(nic, EpromOffset, 0x04);
|
|
set_register(nic, EpromCtrl, 2);
|
|
set_register(nic, EpromCtrl, 0);
|
|
set_register(nic, EpromData, 0);
|
|
|
|
if (!pegasus_reset(nic)) {
|
|
printf("pegasus - device reset failed \n");
|
|
}
|
|
|
|
set_register(nic, 0x80, 0xc0);
|
|
set_register(nic, 0x83, 0xff);
|
|
set_register(nic, 0x84, 0x01);
|
|
set_register(nic, Reg81, 0x02);
|
|
|
|
set_ethernet_addr(nic);
|
|
|
|
strcpy(nic->name, "pegasus");
|
|
|
|
return 1;
|
|
}
|