This driver supports the Altera triple speeds 10/100/1000 ethernet mac. Signed-off-by: Thomas Chou <thomas@wytron.com.tw> Signed-off-by: Ben Warren <biggerbadderben@gmail.com>master
parent
f6569884b4
commit
c960b13ed2
@ -0,0 +1,935 @@ |
||||
/*
|
||||
* Altera 10/100/1000 triple speed ethernet mac driver |
||||
* |
||||
* Copyright (C) 2008 Altera Corporation. |
||||
* Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
#include <config.h> |
||||
#include <common.h> |
||||
#include <malloc.h> |
||||
#include <net.h> |
||||
#include <command.h> |
||||
#include <asm/cache.h> |
||||
#include <asm/dma-mapping.h> |
||||
#include <miiphy.h> |
||||
#include "altera_tse.h" |
||||
|
||||
/* sgdma debug - print descriptor */ |
||||
static void alt_sgdma_print_desc(volatile struct alt_sgdma_descriptor *desc) |
||||
{ |
||||
debug("SGDMA DEBUG :\n"); |
||||
debug("desc->source : 0x%x \n", (unsigned int)desc->source); |
||||
debug("desc->destination : 0x%x \n", (unsigned int)desc->destination); |
||||
debug("desc->next : 0x%x \n", (unsigned int)desc->next); |
||||
debug("desc->source_pad : 0x%x \n", (unsigned int)desc->source_pad); |
||||
debug("desc->destination_pad : 0x%x \n", |
||||
(unsigned int)desc->destination_pad); |
||||
debug("desc->next_pad : 0x%x \n", (unsigned int)desc->next_pad); |
||||
debug("desc->bytes_to_transfer : 0x%x \n", |
||||
(unsigned int)desc->bytes_to_transfer); |
||||
debug("desc->actual_bytes_transferred : 0x%x \n", |
||||
(unsigned int)desc->actual_bytes_transferred); |
||||
debug("desc->descriptor_status : 0x%x \n", |
||||
(unsigned int)desc->descriptor_status); |
||||
debug("desc->descriptor_control : 0x%x \n", |
||||
(unsigned int)desc->descriptor_control); |
||||
} |
||||
|
||||
/* This is a generic routine that the SGDMA mode-specific routines
|
||||
* call to populate a descriptor. |
||||
* arg1 :pointer to first SGDMA descriptor. |
||||
* arg2 :pointer to next SGDMA descriptor. |
||||
* arg3 :Address to where data to be written. |
||||
* arg4 :Address from where data to be read. |
||||
* arg5 :no of byte to transaction. |
||||
* arg6 :variable indicating to generate start of packet or not |
||||
* arg7 :read fixed |
||||
* arg8 :write fixed |
||||
* arg9 :read burst |
||||
* arg10 :write burst |
||||
* arg11 :atlantic_channel number |
||||
*/ |
||||
static void alt_sgdma_construct_descriptor_burst( |
||||
volatile struct alt_sgdma_descriptor *desc, |
||||
volatile struct alt_sgdma_descriptor *next, |
||||
unsigned int *read_addr, |
||||
unsigned int *write_addr, |
||||
unsigned short length_or_eop, |
||||
int generate_eop, |
||||
int read_fixed, |
||||
int write_fixed_or_sop, |
||||
int read_burst, |
||||
int write_burst, |
||||
unsigned char atlantic_channel) |
||||
{ |
||||
/*
|
||||
* Mark the "next" descriptor as "not" owned by hardware. This prevents |
||||
* The SGDMA controller from continuing to process the chain. This is |
||||
* done as a single IO write to bypass cache, without flushing |
||||
* the entire descriptor, since only the 8-bit descriptor status must |
||||
* be flushed. |
||||
*/ |
||||
if (!next) |
||||
debug("Next descriptor not defined!!\n"); |
||||
|
||||
next->descriptor_control = (next->descriptor_control & |
||||
~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK); |
||||
|
||||
desc->source = (unsigned int *)((unsigned int)read_addr & 0x1FFFFFFF); |
||||
desc->destination = |
||||
(unsigned int *)((unsigned int)write_addr & 0x1FFFFFFF); |
||||
desc->next = (unsigned int *)((unsigned int)next & 0x1FFFFFFF); |
||||
desc->source_pad = 0x0; |
||||
desc->destination_pad = 0x0; |
||||
desc->next_pad = 0x0; |
||||
desc->bytes_to_transfer = length_or_eop; |
||||
desc->actual_bytes_transferred = 0; |
||||
desc->descriptor_status = 0x0; |
||||
|
||||
/* SGDMA burst not currently supported */ |
||||
desc->read_burst = 0; |
||||
desc->write_burst = 0; |
||||
|
||||
/*
|
||||
* Set the descriptor control block as follows: |
||||
* - Set "owned by hardware" bit |
||||
* - Optionally set "generate EOP" bit |
||||
* - Optionally set the "read from fixed address" bit |
||||
* - Optionally set the "write to fixed address bit (which serves |
||||
* serves as a "generate SOP" control bit in memory-to-stream mode). |
||||
* - Set the 4-bit atlantic channel, if specified |
||||
* |
||||
* Note this step is performed after all other descriptor information |
||||
* has been filled out so that, if the controller already happens to be |
||||
* pointing at this descriptor, it will not run (via the "owned by |
||||
* hardware" bit) until all other descriptor has been set up. |
||||
*/ |
||||
|
||||
desc->descriptor_control = |
||||
((ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK) | |
||||
(generate_eop ? |
||||
ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK : 0x0) | |
||||
(read_fixed ? |
||||
ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK : 0x0) | |
||||
(write_fixed_or_sop ? |
||||
ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK : 0x0) | |
||||
(atlantic_channel ? ((atlantic_channel & 0x0F) << 3) : 0) |
||||
); |
||||
} |
||||
|
||||
static int alt_sgdma_do_sync_transfer(volatile struct alt_sgdma_registers *dev, |
||||
volatile struct alt_sgdma_descriptor *desc) |
||||
{ |
||||
unsigned int status; |
||||
int counter = 0; |
||||
|
||||
/* Wait for any pending transfers to complete */ |
||||
alt_sgdma_print_desc(desc); |
||||
status = dev->status; |
||||
|
||||
counter = 0; |
||||
while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) { |
||||
if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) |
||||
break; |
||||
} |
||||
|
||||
if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) |
||||
debug("Timeout waiting sgdma in do sync!\n"); |
||||
|
||||
/*
|
||||
* Clear any (previous) status register information |
||||
* that might occlude our error checking later. |
||||
*/ |
||||
dev->status = 0xFF; |
||||
|
||||
/* Point the controller at the descriptor */ |
||||
dev->next_descriptor_pointer = (unsigned int)desc & 0x1FFFFFFF; |
||||
debug("next desc in sgdma 0x%x\n", |
||||
(unsigned int)dev->next_descriptor_pointer); |
||||
|
||||
/*
|
||||
* Set up SGDMA controller to: |
||||
* - Disable interrupt generation |
||||
* - Run once a valid descriptor is written to controller |
||||
* - Stop on an error with any particular descriptor |
||||
*/ |
||||
dev->control = (ALT_SGDMA_CONTROL_RUN_MSK | |
||||
ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK); |
||||
|
||||
/* Wait for the descriptor (chain) to complete */ |
||||
status = dev->status; |
||||
debug("wait for sgdma...."); |
||||
while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) |
||||
; |
||||
debug("done\n"); |
||||
|
||||
/* Clear Run */ |
||||
dev->control = (dev->control & (~ALT_SGDMA_CONTROL_RUN_MSK)); |
||||
|
||||
/* Get & clear status register contents */ |
||||
status = dev->status; |
||||
dev->status = 0xFF; |
||||
|
||||
/* we really should check if the transfer completes properly */ |
||||
debug("tx sgdma status = 0x%x", status); |
||||
return 0; |
||||
} |
||||
|
||||
static int alt_sgdma_do_async_transfer(volatile struct alt_sgdma_registers *dev, |
||||
volatile struct alt_sgdma_descriptor *desc) |
||||
{ |
||||
unsigned int status; |
||||
int counter = 0; |
||||
|
||||
/* Wait for any pending transfers to complete */ |
||||
alt_sgdma_print_desc(desc); |
||||
status = dev->status; |
||||
|
||||
counter = 0; |
||||
while (dev->status & ALT_SGDMA_STATUS_BUSY_MSK) { |
||||
if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) |
||||
break; |
||||
} |
||||
|
||||
if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) |
||||
debug("Timeout waiting sgdma in do async!\n"); |
||||
|
||||
/*
|
||||
* Clear any (previous) status register information |
||||
* that might occlude our error checking later. |
||||
*/ |
||||
dev->status = 0xFF; |
||||
|
||||
/* Point the controller at the descriptor */ |
||||
dev->next_descriptor_pointer = (unsigned int)desc & 0x1FFFFFFF; |
||||
|
||||
/*
|
||||
* Set up SGDMA controller to: |
||||
* - Disable interrupt generation |
||||
* - Run once a valid descriptor is written to controller |
||||
* - Stop on an error with any particular descriptor |
||||
*/ |
||||
dev->control = (ALT_SGDMA_CONTROL_RUN_MSK | |
||||
ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK); |
||||
|
||||
/* we really should check if the transfer completes properly */ |
||||
return 0; |
||||
} |
||||
|
||||
/* u-boot interface */ |
||||
static int tse_adjust_link(struct altera_tse_priv *priv) |
||||
{ |
||||
unsigned int refvar; |
||||
|
||||
refvar = priv->mac_dev->command_config.image; |
||||
|
||||
if (!(priv->duplexity)) |
||||
refvar |= ALTERA_TSE_CMD_HD_ENA_MSK; |
||||
else |
||||
refvar &= ~ALTERA_TSE_CMD_HD_ENA_MSK; |
||||
|
||||
switch (priv->speed) { |
||||
case 1000: |
||||
refvar |= ALTERA_TSE_CMD_ETH_SPEED_MSK; |
||||
refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; |
||||
break; |
||||
case 100: |
||||
refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; |
||||
refvar &= ~ALTERA_TSE_CMD_ENA_10_MSK; |
||||
break; |
||||
case 10: |
||||
refvar &= ~ALTERA_TSE_CMD_ETH_SPEED_MSK; |
||||
refvar |= ALTERA_TSE_CMD_ENA_10_MSK; |
||||
break; |
||||
} |
||||
priv->mac_dev->command_config.image = refvar; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int tse_eth_send(struct eth_device *dev, |
||||
volatile void *packet, int length) |
||||
{ |
||||
struct altera_tse_priv *priv = dev->priv; |
||||
volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; |
||||
volatile struct alt_sgdma_descriptor *tx_desc = |
||||
(volatile struct alt_sgdma_descriptor *)priv->tx_desc; |
||||
|
||||
volatile struct alt_sgdma_descriptor *tx_desc_cur = |
||||
(volatile struct alt_sgdma_descriptor *)&tx_desc[0]; |
||||
|
||||
flush_dcache((unsigned long)packet, length); |
||||
alt_sgdma_construct_descriptor_burst( |
||||
(volatile struct alt_sgdma_descriptor *)&tx_desc[0], |
||||
(volatile struct alt_sgdma_descriptor *)&tx_desc[1], |
||||
(unsigned int *)packet, /* read addr */ |
||||
(unsigned int *)0, |
||||
length, /* length or EOP ,will change for each tx */ |
||||
0x1, /* gen eop */ |
||||
0x0, /* read fixed */ |
||||
0x1, /* write fixed or sop */ |
||||
0x0, /* read burst */ |
||||
0x0, /* write burst */ |
||||
0x0 /* channel */ |
||||
); |
||||
debug("TX Packet @ 0x%x,0x%x bytes", (unsigned int)packet, length); |
||||
|
||||
/* send the packet */ |
||||
debug("sending packet\n"); |
||||
alt_sgdma_do_sync_transfer(tx_sgdma, tx_desc_cur); |
||||
debug("sent %d bytes\n", tx_desc_cur->actual_bytes_transferred); |
||||
return tx_desc_cur->actual_bytes_transferred; |
||||
} |
||||
|
||||
static int tse_eth_rx(struct eth_device *dev) |
||||
{ |
||||
int packet_length = 0; |
||||
struct altera_tse_priv *priv = dev->priv; |
||||
volatile struct alt_sgdma_descriptor *rx_desc = |
||||
(volatile struct alt_sgdma_descriptor *)priv->rx_desc; |
||||
volatile struct alt_sgdma_descriptor *rx_desc_cur = &rx_desc[0]; |
||||
|
||||
if (rx_desc_cur->descriptor_status & |
||||
ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) { |
||||
debug("got packet\n"); |
||||
packet_length = rx_desc->actual_bytes_transferred; |
||||
NetReceive(NetRxPackets[0], packet_length); |
||||
|
||||
/* start descriptor again */ |
||||
flush_dcache((unsigned long)(NetRxPackets[0]), PKTSIZE_ALIGN); |
||||
alt_sgdma_construct_descriptor_burst( |
||||
(volatile struct alt_sgdma_descriptor *)&rx_desc[0], |
||||
(volatile struct alt_sgdma_descriptor *)&rx_desc[1], |
||||
(unsigned int)0x0, /* read addr */ |
||||
(unsigned int *)NetRxPackets[0], |
||||
0x0, /* length or EOP */ |
||||
0x0, /* gen eop */ |
||||
0x0, /* read fixed */ |
||||
0x0, /* write fixed or sop */ |
||||
0x0, /* read burst */ |
||||
0x0, /* write burst */ |
||||
0x0 /* channel */ |
||||
); |
||||
|
||||
/* setup the sgdma */ |
||||
alt_sgdma_do_async_transfer(priv->sgdma_rx, &rx_desc[0]); |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
static void tse_eth_halt(struct eth_device *dev) |
||||
{ |
||||
/* don't do anything! */ |
||||
/* this gets called after each uboot */ |
||||
/* network command. don't need to reset the thing all of the time */ |
||||
} |
||||
|
||||
static void tse_eth_reset(struct eth_device *dev) |
||||
{ |
||||
/* stop sgdmas, disable tse receive */ |
||||
struct altera_tse_priv *priv = dev->priv; |
||||
volatile struct alt_tse_mac *mac_dev = priv->mac_dev; |
||||
volatile struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx; |
||||
volatile struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx; |
||||
int counter; |
||||
volatile struct alt_sgdma_descriptor *rx_desc = |
||||
(volatile struct alt_sgdma_descriptor *)&priv->rx_desc[0]; |
||||
|
||||
/* clear rx desc & wait for sgdma to complete */ |
||||
rx_desc->descriptor_control = 0; |
||||
rx_sgdma->control = 0; |
||||
counter = 0; |
||||
while (rx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) { |
||||
if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) |
||||
break; |
||||
} |
||||
|
||||
if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { |
||||
debug("Timeout waiting for rx sgdma!\n"); |
||||
rx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; |
||||
rx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; |
||||
} |
||||
|
||||
counter = 0; |
||||
tx_sgdma->control = 0; |
||||
while (tx_sgdma->status & ALT_SGDMA_STATUS_BUSY_MSK) { |
||||
if (counter++ > ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) |
||||
break; |
||||
} |
||||
|
||||
if (counter >= ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR) { |
||||
debug("Timeout waiting for tx sgdma!\n"); |
||||
tx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; |
||||
tx_sgdma->control &= ALT_SGDMA_CONTROL_SOFTWARERESET_MSK; |
||||
} |
||||
/* reset the mac */ |
||||
mac_dev->command_config.bits.transmit_enable = 1; |
||||
mac_dev->command_config.bits.receive_enable = 1; |
||||
mac_dev->command_config.bits.software_reset = 1; |
||||
|
||||
counter = 0; |
||||
while (mac_dev->command_config.bits.software_reset) { |
||||
if (counter++ > ALT_TSE_SW_RESET_WATCHDOG_CNTR) |
||||
break; |
||||
} |
||||
|
||||
if (counter >= ALT_TSE_SW_RESET_WATCHDOG_CNTR) |
||||
debug("TSEMAC SW reset bit never cleared!\n"); |
||||
} |
||||
|
||||
static int tse_mdio_read(struct altera_tse_priv *priv, unsigned int regnum) |
||||
{ |
||||
volatile struct alt_tse_mac *mac_dev; |
||||
unsigned int *mdio_regs; |
||||
unsigned int data; |
||||
u16 value; |
||||
|
||||
mac_dev = priv->mac_dev; |
||||
|
||||
/* set mdio address */ |
||||
mac_dev->mdio_phy1_addr = priv->phyaddr; |
||||
mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; |
||||
|
||||
/* get the data */ |
||||
data = mdio_regs[regnum]; |
||||
|
||||
value = data & 0xffff; |
||||
|
||||
return value; |
||||
} |
||||
|
||||
static int tse_mdio_write(struct altera_tse_priv *priv, unsigned int regnum, |
||||
unsigned int value) |
||||
{ |
||||
volatile struct alt_tse_mac *mac_dev; |
||||
unsigned int *mdio_regs; |
||||
unsigned int data; |
||||
|
||||
mac_dev = priv->mac_dev; |
||||
|
||||
/* set mdio address */ |
||||
mac_dev->mdio_phy1_addr = priv->phyaddr; |
||||
mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; |
||||
|
||||
/* get the data */ |
||||
data = (unsigned int)value; |
||||
|
||||
mdio_regs[regnum] = data; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* MDIO access to phy */ |
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII) |
||||
static int altera_tse_miiphy_write(char *devname, unsigned char addr, |
||||
unsigned char reg, unsigned short value) |
||||
{ |
||||
struct eth_device *dev; |
||||
struct altera_tse_priv *priv; |
||||
dev = eth_get_dev_by_name(devname); |
||||
priv = dev->priv; |
||||
|
||||
tse_mdio_write(priv, (uint) reg, (uint) value); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int altera_tse_miiphy_read(char *devname, unsigned char addr, |
||||
unsigned char reg, unsigned short *value) |
||||
{ |
||||
struct eth_device *dev; |
||||
struct altera_tse_priv *priv; |
||||
volatile struct alt_tse_mac *mac_dev; |
||||
unsigned int *mdio_regs; |
||||
|
||||
dev = eth_get_dev_by_name(devname); |
||||
priv = dev->priv; |
||||
|
||||
mac_dev = priv->mac_dev; |
||||
mac_dev->mdio_phy1_addr = (int)addr; |
||||
mdio_regs = (unsigned int *)&mac_dev->mdio_phy1; |
||||
|
||||
*value = 0xffff & mdio_regs[reg]; |
||||
|
||||
return 0; |
||||
|
||||
} |
||||
#endif |
||||
|
||||
/*
|
||||
* Also copied from tsec.c |
||||
*/ |
||||
/* Parse the status register for link, and then do
|
||||
* auto-negotiation |
||||
*/ |
||||
static uint mii_parse_sr(uint mii_reg, struct altera_tse_priv *priv) |
||||
{ |
||||
/*
|
||||
* Wait if the link is up, and autonegotiation is in progress |
||||
* (ie - we're capable and it's not done) |
||||
*/ |
||||
mii_reg = tse_mdio_read(priv, MIIM_STATUS); |
||||
|
||||
if (!(mii_reg & MIIM_STATUS_LINK) && (mii_reg & PHY_BMSR_AUTN_ABLE) |
||||
&& !(mii_reg & PHY_BMSR_AUTN_COMP)) { |
||||
int i = 0; |
||||
|
||||
puts("Waiting for PHY auto negotiation to complete"); |
||||
while (!(mii_reg & PHY_BMSR_AUTN_COMP)) { |
||||
/*
|
||||
* Timeout reached ? |
||||
*/ |
||||
if (i > PHY_AUTONEGOTIATE_TIMEOUT) { |
||||
puts(" TIMEOUT !\n"); |
||||
priv->link = 0; |
||||
return 0; |
||||
} |
||||
|
||||
if ((i++ % 1000) == 0) |
||||
putc('.'); |
||||
udelay(1000); /* 1 ms */ |
||||
mii_reg = tse_mdio_read(priv, MIIM_STATUS); |
||||
} |
||||
puts(" done\n"); |
||||
priv->link = 1; |
||||
udelay(500000); /* another 500 ms (results in faster booting) */ |
||||
} else { |
||||
if (mii_reg & MIIM_STATUS_LINK) { |
||||
debug("Link is up\n"); |
||||
priv->link = 1; |
||||
} else { |
||||
debug("Link is down\n"); |
||||
priv->link = 0; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/* Parse the 88E1011's status register for speed and duplex
|
||||
* information |
||||
*/ |
||||
static uint mii_parse_88E1011_psr(uint mii_reg, struct altera_tse_priv *priv) |
||||
{ |
||||
uint speed; |
||||
|
||||
mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); |
||||
|
||||
if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) && |
||||
!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { |
||||
int i = 0; |
||||
|
||||
puts("Waiting for PHY realtime link"); |
||||
while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { |
||||
/* Timeout reached ? */ |
||||
if (i > PHY_AUTONEGOTIATE_TIMEOUT) { |
||||
puts(" TIMEOUT !\n"); |
||||
priv->link = 0; |
||||
break; |
||||
} |
||||
|
||||
if ((i++ == 1000) == 0) { |
||||
i = 0; |
||||
puts("."); |
||||
} |
||||
udelay(1000); /* 1 ms */ |
||||
mii_reg = tse_mdio_read(priv, MIIM_88E1011_PHY_STATUS); |
||||
} |
||||
puts(" done\n"); |
||||
udelay(500000); /* another 500 ms (results in faster booting) */ |
||||
} else { |
||||
if (mii_reg & MIIM_88E1011_PHYSTAT_LINK) |
||||
priv->link = 1; |
||||
else |
||||
priv->link = 0; |
||||
} |
||||
|
||||
if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) |
||||
priv->duplexity = 1; |
||||
else |
||||
priv->duplexity = 0; |
||||
|
||||
speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED); |
||||
|
||||
switch (speed) { |
||||
case MIIM_88E1011_PHYSTAT_GBIT: |
||||
priv->speed = 1000; |
||||
debug("PHY Speed is 1000Mbit\n"); |
||||
break; |
||||
case MIIM_88E1011_PHYSTAT_100: |
||||
debug("PHY Speed is 100Mbit\n"); |
||||
priv->speed = 100; |
||||
break; |
||||
default: |
||||
debug("PHY Speed is 10Mbit\n"); |
||||
priv->speed = 10; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static uint mii_m88e1111s_setmode_sr(uint mii_reg, struct altera_tse_priv *priv) |
||||
{ |
||||
uint mii_data = tse_mdio_read(priv, mii_reg); |
||||
mii_data &= 0xfff0; |
||||
mii_data |= 0xb; |
||||
return mii_data; |
||||
} |
||||
|
||||
static uint mii_m88e1111s_setmode_cr(uint mii_reg, struct altera_tse_priv *priv) |
||||
{ |
||||
uint mii_data = tse_mdio_read(priv, mii_reg); |
||||
mii_data &= ~0x82; |
||||
mii_data |= 0x82; |
||||
return mii_data; |
||||
} |
||||
|
||||
/*
|
||||
* Returns which value to write to the control register. |
||||
* For 10/100, the value is slightly different |
||||
*/ |
||||
static uint mii_cr_init(uint mii_reg, struct altera_tse_priv *priv) |
||||
{ |
||||
return MIIM_CONTROL_INIT; |
||||
} |
||||
|
||||
/*
|
||||
* PHY & MDIO code |
||||
* Need to add SGMII stuff |
||||
* |
||||
*/ |
||||
|
||||
static struct phy_info phy_info_M88E1111S = { |
||||
0x01410cc, |
||||
"Marvell 88E1111S", |
||||
4, |
||||
(struct phy_cmd[]){ /* config */ |
||||
/* Reset and configure the PHY */ |
||||
{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, |
||||
{MIIM_88E1111_PHY_EXT_SR, 0x848f, |
||||
&mii_m88e1111s_setmode_sr}, |
||||
/* Delay RGMII TX and RX */ |
||||
{MIIM_88E1111_PHY_EXT_CR, 0x0cd2, |
||||
&mii_m88e1111s_setmode_cr}, |
||||
{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, |
||||
{MIIM_ANAR, MIIM_ANAR_INIT, NULL}, |
||||
{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, |
||||
{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, |
||||
{miim_end,} |
||||
}, |
||||
(struct phy_cmd[]){ /* startup */ |
||||
/* Status is read once to clear old link state */ |
||||
{MIIM_STATUS, miim_read, NULL}, |
||||
/* Auto-negotiate */ |
||||
{MIIM_STATUS, miim_read, &mii_parse_sr}, |
||||
/* Read the status */ |
||||
{MIIM_88E1011_PHY_STATUS, miim_read, |
||||
&mii_parse_88E1011_psr}, |
||||
{miim_end,} |
||||
}, |
||||
(struct phy_cmd[]){ /* shutdown */ |
||||
{miim_end,} |
||||
}, |
||||
}; |
||||
|
||||
/* a generic flavor. */ |
||||
static struct phy_info phy_info_generic = { |
||||
0, |
||||
"Unknown/Generic PHY", |
||||
32, |
||||
(struct phy_cmd[]){ /* config */ |
||||
{PHY_BMCR, PHY_BMCR_RESET, NULL}, |
||||
{PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG, NULL}, |
||||
{miim_end,} |
||||
}, |
||||
(struct phy_cmd[]){ /* startup */ |
||||
{PHY_BMSR, miim_read, NULL}, |
||||
{PHY_BMSR, miim_read, &mii_parse_sr}, |
||||
{miim_end,} |
||||
}, |
||||
(struct phy_cmd[]){ /* shutdown */ |
||||
{miim_end,} |
||||
} |
||||
}; |
||||
|
||||
static struct phy_info *phy_info[] = { |
||||
&phy_info_M88E1111S, |
||||
NULL |
||||
}; |
||||
|
||||
/* Grab the identifier of the device's PHY, and search through
|
||||
* all of the known PHYs to see if one matches. If so, return |
||||
* it, if not, return NULL |
||||
*/ |
||||
static struct phy_info *get_phy_info(struct eth_device *dev) |
||||
{ |
||||
struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; |
||||
uint phy_reg, phy_ID; |
||||
int i; |
||||
struct phy_info *theInfo = NULL; |
||||
|
||||
/* Grab the bits from PHYIR1, and put them in the upper half */ |
||||
phy_reg = tse_mdio_read(priv, MIIM_PHYIR1); |
||||
phy_ID = (phy_reg & 0xffff) << 16; |
||||
|
||||
/* Grab the bits from PHYIR2, and put them in the lower half */ |
||||
phy_reg = tse_mdio_read(priv, MIIM_PHYIR2); |
||||
phy_ID |= (phy_reg & 0xffff); |
||||
|
||||
/* loop through all the known PHY types, and find one that */ |
||||
/* matches the ID we read from the PHY. */ |
||||
for (i = 0; phy_info[i]; i++) { |
||||
if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) { |
||||
theInfo = phy_info[i]; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (theInfo == NULL) { |
||||
theInfo = &phy_info_generic; |
||||
debug("%s: No support for PHY id %x; assuming generic\n", |
||||
dev->name, phy_ID); |
||||
} else |
||||
debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID); |
||||
|
||||
return theInfo; |
||||
} |
||||
|
||||
/* Execute the given series of commands on the given device's
|
||||
* PHY, running functions as necessary |
||||
*/ |
||||
static void phy_run_commands(struct altera_tse_priv *priv, struct phy_cmd *cmd) |
||||
{ |
||||
int i; |
||||
uint result; |
||||
|
||||
for (i = 0; cmd->mii_reg != miim_end; i++) { |
||||
if (cmd->mii_data == miim_read) { |
||||
result = tse_mdio_read(priv, cmd->mii_reg); |
||||
|
||||
if (cmd->funct != NULL) |
||||
(*(cmd->funct)) (result, priv); |
||||
|
||||
} else { |
||||
if (cmd->funct != NULL) |
||||
result = (*(cmd->funct)) (cmd->mii_reg, priv); |
||||
else |
||||
result = cmd->mii_data; |
||||
|
||||
tse_mdio_write(priv, cmd->mii_reg, result); |
||||
|
||||
} |
||||
cmd++; |
||||
} |
||||
} |
||||
|
||||
/* Phy init code */ |
||||
static int init_phy(struct eth_device *dev) |
||||
{ |
||||
struct altera_tse_priv *priv = (struct altera_tse_priv *)dev->priv; |
||||
struct phy_info *curphy; |
||||
|
||||
/* Get the cmd structure corresponding to the attached
|
||||
* PHY */ |
||||
curphy = get_phy_info(dev); |
||||
|
||||
if (curphy == NULL) { |
||||
priv->phyinfo = NULL; |
||||
debug("%s: No PHY found\n", dev->name); |
||||
|
||||
return 0; |
||||
} else |
||||
debug("%s found\n", curphy->name); |
||||
priv->phyinfo = curphy; |
||||
|
||||
phy_run_commands(priv, priv->phyinfo->config); |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
static int tse_eth_init(struct eth_device *dev, bd_t * bd) |
||||
{ |
||||
int dat; |
||||
struct altera_tse_priv *priv = dev->priv; |
||||
volatile struct alt_tse_mac *mac_dev = priv->mac_dev; |
||||
volatile struct alt_sgdma_descriptor *tx_desc = priv->tx_desc; |
||||
volatile struct alt_sgdma_descriptor *rx_desc = priv->rx_desc; |
||||
volatile struct alt_sgdma_descriptor *rx_desc_cur = |
||||
(volatile struct alt_sgdma_descriptor *)&rx_desc[0]; |
||||
|
||||
/* stop controller */ |
||||
debug("Reseting TSE & SGDMAs\n"); |
||||
tse_eth_reset(dev); |
||||
|
||||
/* start the phy */ |
||||
debug("Configuring PHY\n"); |
||||
phy_run_commands(priv, priv->phyinfo->startup); |
||||
|
||||
/* need to create sgdma */ |
||||
debug("Configuring tx desc\n"); |
||||
alt_sgdma_construct_descriptor_burst( |
||||
(volatile struct alt_sgdma_descriptor *)&tx_desc[0], |
||||
(volatile struct alt_sgdma_descriptor *)&tx_desc[1], |
||||
(unsigned int *)NULL, /* read addr */ |
||||
(unsigned int *)0, |
||||
0, /* length or EOP ,will change for each tx */ |
||||
0x1, /* gen eop */ |
||||
0x0, /* read fixed */ |
||||
0x1, /* write fixed or sop */ |
||||
0x0, /* read burst */ |
||||
0x0, /* write burst */ |
||||
0x0 /* channel */ |
||||
); |
||||
debug("Configuring rx desc\n"); |
||||
flush_dcache((unsigned long)(NetRxPackets[0]), PKTSIZE_ALIGN); |
||||
alt_sgdma_construct_descriptor_burst( |
||||
(volatile struct alt_sgdma_descriptor *)&rx_desc[0], |
||||
(volatile struct alt_sgdma_descriptor *)&rx_desc[1], |
||||
(unsigned int)0x0, /* read addr */ |
||||
(unsigned int *)NetRxPackets[0], |
||||
0x0, /* length or EOP */ |
||||
0x0, /* gen eop */ |
||||
0x0, /* read fixed */ |
||||
0x0, /* write fixed or sop */ |
||||
0x0, /* read burst */ |
||||
0x0, /* write burst */ |
||||
0x0 /* channel */ |
||||
); |
||||
/* start rx async transfer */ |
||||
debug("Starting rx sgdma\n"); |
||||
alt_sgdma_do_async_transfer(priv->sgdma_rx, rx_desc_cur); |
||||
|
||||
/* start TSE */ |
||||
debug("Configuring TSE Mac\n"); |
||||
/* Initialize MAC registers */ |
||||
mac_dev->max_frame_length = PKTSIZE_ALIGN; |
||||
mac_dev->rx_almost_empty_threshold = 8; |
||||
mac_dev->rx_almost_full_threshold = 8; |
||||
mac_dev->tx_almost_empty_threshold = 8; |
||||
mac_dev->tx_almost_full_threshold = 3; |
||||
mac_dev->tx_sel_empty_threshold = |
||||
CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16; |
||||
mac_dev->tx_sel_full_threshold = 0; |
||||
mac_dev->rx_sel_empty_threshold = |
||||
CONFIG_SYS_ALTERA_TSE_TX_FIFO - 16; |
||||
mac_dev->rx_sel_full_threshold = 0; |
||||
|
||||
/* NO Shift */ |
||||
mac_dev->rx_cmd_stat.bits.rx_shift16 = 0; |
||||
mac_dev->tx_cmd_stat.bits.tx_shift16 = 0; |
||||
|
||||
/* enable MAC */ |
||||
dat = 0; |
||||
dat = ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK; |
||||
|
||||
mac_dev->command_config.image = dat; |
||||
|
||||
/* Set the MAC address */ |
||||
debug("Setting MAC address to 0x%x%x%x%x%x%x\n", |
||||
dev->enetaddr[5], dev->enetaddr[4], |
||||
dev->enetaddr[3], dev->enetaddr[2], |
||||
dev->enetaddr[1], dev->enetaddr[0]); |
||||
mac_dev->mac_addr_0 = ((dev->enetaddr[3]) << 24 | |
||||
(dev->enetaddr[2]) << 16 | |
||||
(dev->enetaddr[1]) << 8 | (dev->enetaddr[0])); |
||||
|
||||
mac_dev->mac_addr_1 = ((dev->enetaddr[5] << 8 | |
||||
(dev->enetaddr[4])) & 0xFFFF); |
||||
|
||||
/* Set the MAC address */ |
||||
mac_dev->supp_mac_addr_0_0 = mac_dev->mac_addr_0; |
||||
mac_dev->supp_mac_addr_0_1 = mac_dev->mac_addr_1; |
||||
|
||||
/* Set the MAC address */ |
||||
mac_dev->supp_mac_addr_1_0 = mac_dev->mac_addr_0; |
||||
mac_dev->supp_mac_addr_1_1 = mac_dev->mac_addr_1; |
||||
|
||||
/* Set the MAC address */ |
||||
mac_dev->supp_mac_addr_2_0 = mac_dev->mac_addr_0; |
||||
mac_dev->supp_mac_addr_2_1 = mac_dev->mac_addr_1; |
||||
|
||||
/* Set the MAC address */ |
||||
mac_dev->supp_mac_addr_3_0 = mac_dev->mac_addr_0; |
||||
mac_dev->supp_mac_addr_3_1 = mac_dev->mac_addr_1; |
||||
|
||||
/* configure the TSE core */ |
||||
/* -- output clocks, */ |
||||
/* -- and later config stuff for SGMII */ |
||||
if (priv->link) { |
||||
debug("Adjusting TSE to link speed\n"); |
||||
tse_adjust_link(priv); |
||||
} |
||||
|
||||
return priv->link ? 0 : -1; |
||||
} |
||||
|
||||
/* TSE init code */ |
||||
int altera_tse_initialize(u8 dev_num, int mac_base, |
||||
int sgdma_rx_base, int sgdma_tx_base) |
||||
{ |
||||
struct altera_tse_priv *priv; |
||||
struct eth_device *dev; |
||||
struct alt_sgdma_descriptor *rx_desc; |
||||
struct alt_sgdma_descriptor *tx_desc; |
||||
unsigned long dma_handle; |
||||
|
||||
dev = (struct eth_device *)malloc(sizeof *dev); |
||||
|
||||
if (NULL == dev) |
||||
return 0; |
||||
|
||||
memset(dev, 0, sizeof *dev); |
||||
|
||||
priv = malloc(sizeof(*priv)); |
||||
|
||||
if (!priv) { |
||||
free(dev); |
||||
return 0; |
||||
} |
||||
tx_desc = dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX), |
||||
&dma_handle); |
||||
rx_desc = tx_desc + 2; |
||||
debug("tx desc: address = 0x%x\n", (unsigned int)tx_desc); |
||||
debug("rx desc: address = 0x%x\n", (unsigned int)rx_desc); |
||||
|
||||
if (!tx_desc) { |
||||
free(priv); |
||||
free(dev); |
||||
return 0; |
||||
} |
||||
memset(rx_desc, 0, (sizeof *rx_desc) * (PKTBUFSRX + 1)); |
||||
memset(tx_desc, 0, (sizeof *tx_desc) * 2); |
||||
|
||||
/* initialize tse priv */ |
||||
priv->mac_dev = (volatile struct alt_tse_mac *)mac_base; |
||||
priv->sgdma_rx = (volatile struct alt_sgdma_registers *)sgdma_rx_base; |
||||
priv->sgdma_tx = (volatile struct alt_sgdma_registers *)sgdma_tx_base; |
||||
priv->phyaddr = CONFIG_SYS_ALTERA_TSE_PHY_ADDR; |
||||
priv->flags = CONFIG_SYS_ALTERA_TSE_FLAGS; |
||||
priv->rx_desc = rx_desc; |
||||
priv->tx_desc = tx_desc; |
||||
|
||||
/* init eth structure */ |
||||
dev->priv = priv; |
||||
dev->init = tse_eth_init; |
||||
dev->halt = tse_eth_halt; |
||||
dev->send = tse_eth_send; |
||||
dev->recv = tse_eth_rx; |
||||
sprintf(dev->name, "%s-%hu", "ALTERA_TSE", dev_num); |
||||
|
||||
eth_register(dev); |
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII) |
||||
miiphy_register(dev->name, altera_tse_miiphy_read, |
||||
altera_tse_miiphy_write); |
||||
#endif |
||||
|
||||
init_phy(dev); |
||||
|
||||
return 1; |
||||
} |
@ -0,0 +1,494 @@ |
||||
/*
|
||||
* Altera 10/100/1000 triple speed ethernet mac |
||||
* |
||||
* Copyright (C) 2008 Altera Corporation. |
||||
* Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License version 2 as |
||||
* published by the Free Software Foundation. |
||||
*/ |
||||
#ifndef _ALTERA_TSE_H_ |
||||
#define _ALTERA_TSE_H_ |
||||
|
||||
#define __packed_1_ __attribute__ ((packed, aligned(1))) |
||||
|
||||
/* PHY Stuff */ |
||||
#define miim_end -2 |
||||
#define miim_read -1 |
||||
|
||||
#define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* in ms */ |
||||
|
||||
#ifndef CONFIG_SYS_TBIPA_VALUE |
||||
#define CONFIG_SYS_TBIPA_VALUE 0x1f |
||||
#endif |
||||
#define MIIMCFG_INIT_VALUE 0x00000003 |
||||
#define MIIMCFG_RESET 0x80000000 |
||||
|
||||
#define MIIMIND_BUSY 0x00000001 |
||||
#define MIIMIND_NOTVALID 0x00000004 |
||||
|
||||
#define MIIM_CONTROL 0x00 |
||||
#define MIIM_CONTROL_RESET 0x00009140 |
||||
#define MIIM_CONTROL_INIT 0x00001140 |
||||
#define MIIM_CONTROL_RESTART 0x00001340 |
||||
#define MIIM_ANEN 0x00001000 |
||||
|
||||
#define MIIM_CR 0x00 |
||||
#define MIIM_CR_RST 0x00008000 |
||||
#define MIIM_CR_INIT 0x00001000 |
||||
|
||||
#define MIIM_STATUS 0x1 |
||||
#define MIIM_STATUS_AN_DONE 0x00000020 |
||||
#define MIIM_STATUS_LINK 0x0004 |
||||
#define PHY_BMSR_AUTN_ABLE 0x0008 |
||||
#define PHY_BMSR_AUTN_COMP 0x0020 |
||||
|
||||
#define MIIM_PHYIR1 0x2 |
||||
#define MIIM_PHYIR2 0x3 |
||||
|
||||
#define MIIM_ANAR 0x4 |
||||
#define MIIM_ANAR_INIT 0x1e1 |
||||
|
||||
#define MIIM_TBI_ANLPBPA 0x5 |
||||
#define MIIM_TBI_ANLPBPA_HALF 0x00000040 |
||||
#define MIIM_TBI_ANLPBPA_FULL 0x00000020 |
||||
|
||||
#define MIIM_TBI_ANEX 0x6 |
||||
#define MIIM_TBI_ANEX_NP 0x00000004 |
||||
#define MIIM_TBI_ANEX_PRX 0x00000002 |
||||
|
||||
#define MIIM_GBIT_CONTROL 0x9 |
||||
#define MIIM_GBIT_CONTROL_INIT 0xe00 |
||||
|
||||
#define MIIM_EXT_PAGE_ACCESS 0x1f |
||||
|
||||
/* 88E1011 PHY Status Register */ |
||||
#define MIIM_88E1011_PHY_STATUS 0x11 |
||||
#define MIIM_88E1011_PHYSTAT_SPEED 0xc000 |
||||
#define MIIM_88E1011_PHYSTAT_GBIT 0x8000 |
||||
#define MIIM_88E1011_PHYSTAT_100 0x4000 |
||||
#define MIIM_88E1011_PHYSTAT_DUPLEX 0x2000 |
||||
#define MIIM_88E1011_PHYSTAT_SPDDONE 0x0800 |
||||
#define MIIM_88E1011_PHYSTAT_LINK 0x0400 |
||||
|
||||
#define MIIM_88E1011_PHY_SCR 0x10 |
||||
#define MIIM_88E1011_PHY_MDI_X_AUTO 0x0060 |
||||
|
||||
#define MIIM_88E1111_PHY_EXT_CR 0x14 |
||||
#define MIIM_88E1111_PHY_EXT_SR 0x1b |
||||
|
||||
/* 88E1111 PHY LED Control Register */ |
||||
#define MIIM_88E1111_PHY_LED_CONTROL 24 |
||||
#define MIIM_88E1111_PHY_LED_DIRECT 0x4100 |
||||
#define MIIM_88E1111_PHY_LED_COMBINE 0x411C |
||||
|
||||
#define MIIM_READ_COMMAND 0x00000001 |
||||
|
||||
/* struct phy_info: a structure which defines attributes for a PHY
|
||||
* id will contain a number which represents the PHY. During |
||||
* startup, the driver will poll the PHY to find out what its |
||||
* UID--as defined by registers 2 and 3--is. The 32-bit result |
||||
* gotten from the PHY will be shifted right by "shift" bits to |
||||
* discard any bits which may change based on revision numbers |
||||
* unimportant to functionality |
||||
* |
||||
* The struct phy_cmd entries represent pointers to an arrays of |
||||
* commands which tell the driver what to do to the PHY. |
||||
*/ |
||||
struct phy_info { |
||||
uint id; |
||||
char *name; |
||||
uint shift; |
||||
/* Called to configure the PHY, and modify the controller
|
||||
* based on the results */ |
||||
struct phy_cmd *config; |
||||
|
||||
/* Called when starting up the controller */ |
||||
struct phy_cmd *startup; |
||||
|
||||
/* Called when bringing down the controller */ |
||||
struct phy_cmd *shutdown; |
||||
}; |
||||
|
||||
/* SGDMA Stuff */ |
||||
#define ALT_SGDMA_STATUS_ERROR_MSK (0x00000001) |
||||
#define ALT_SGDMA_STATUS_EOP_ENCOUNTERED_MSK (0x00000002) |
||||
#define ALT_SGDMA_STATUS_DESC_COMPLETED_MSK (0x00000004) |
||||
#define ALT_SGDMA_STATUS_CHAIN_COMPLETED_MSK (0x00000008) |
||||
#define ALT_SGDMA_STATUS_BUSY_MSK (0x00000010) |
||||
|
||||
#define ALT_SGDMA_CONTROL_IE_ERROR_MSK (0x00000001) |
||||
#define ALT_SGDMA_CONTROL_IE_EOP_ENCOUNTERED_MSK (0x00000002) |
||||
#define ALT_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK (0x00000004) |
||||
#define ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK (0x00000008) |
||||
#define ALT_SGDMA_CONTROL_IE_GLOBAL_MSK (0x00000010) |
||||
#define ALT_SGDMA_CONTROL_RUN_MSK (0x00000020) |
||||
#define ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK (0x00000040) |
||||
#define ALT_SGDMA_CONTROL_IE_MAX_DESC_PROCESSED_MSK (0x00000080) |
||||
#define ALT_SGDMA_CONTROL_MAX_DESC_PROCESSED_MSK (0x0000FF00) |
||||
#define ALT_SGDMA_CONTROL_SOFTWARERESET_MSK (0x00010000) |
||||
#define ALT_SGDMA_CONTROL_PARK_MSK (0x00020000) |
||||
#define ALT_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK (0x80000000) |
||||
|
||||
#define ALTERA_TSE_SGDMA_INTR_MASK (ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK \ |
||||
| ALT_SGDMA_STATUS_DESC_COMPLETED_MSK \
|
||||
| ALT_SGDMA_CONTROL_IE_GLOBAL_MSK) |
||||
|
||||
/*
|
||||
* Descriptor control bit masks & offsets |
||||
* |
||||
* Note: The control byte physically occupies bits [31:24] in memory. |
||||
* The following bit-offsets are expressed relative to the LSB of |
||||
* the control register bitfield. |
||||
*/ |
||||
#define ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK (0x00000001) |
||||
#define ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK (0x00000002) |
||||
#define ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK (0x00000004) |
||||
#define ALT_SGDMA_DESCRIPTOR_CONTROL_ATLANTIC_CHANNEL_MSK (0x00000008) |
||||
#define ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK (0x00000080) |
||||
|
||||
/*
|
||||
* Descriptor status bit masks & offsets |
||||
* |
||||
* Note: The status byte physically occupies bits [23:16] in memory. |
||||
* The following bit-offsets are expressed relative to the LSB of |
||||
* the status register bitfield. |
||||
*/ |
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK (0x00000001) |
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK (0x00000002) |
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK (0x00000004) |
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK (0x00000008) |
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK (0x00000010) |
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK (0x00000020) |
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK (0x00000040) |
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK (0x00000080) |
||||
#define ALT_SGDMA_DESCRIPTOR_STATUS_ERROR_MSK (0x0000007F) |
||||
|
||||
/*
|
||||
* The SGDMA controller buffer descriptor allocates |
||||
* 64 bits for each address. To support ANSI C, the |
||||
* struct implementing a descriptor places 32-bits |
||||
* of padding directly above each address; each pad must |
||||
* be cleared when initializing a descriptor. |
||||
*/ |
||||
|
||||
/*
|
||||
* Buffer Descriptor data structure |
||||
* |
||||
*/ |
||||
struct alt_sgdma_descriptor { |
||||
unsigned int *source; /* the address of data to be read. */ |
||||
unsigned int source_pad; |
||||
|
||||
unsigned int *destination; /* the address to write data */ |
||||
unsigned int destination_pad; |
||||
|
||||
unsigned int *next; /* the next descriptor in the list. */ |
||||
unsigned int next_pad; |
||||
|
||||
unsigned short bytes_to_transfer; /* the number of bytes to transfer */ |
||||
unsigned char read_burst; |
||||
unsigned char write_burst; |
||||
|
||||
unsigned short actual_bytes_transferred;/* bytes transferred by DMA */ |
||||
unsigned char descriptor_status; |
||||
unsigned char descriptor_control; |
||||
|
||||
} __packed_1_; |
||||
|
||||
/* SG-DMA Control/Status Slave registers map */ |
||||
|
||||
struct alt_sgdma_registers { |
||||
unsigned int status; |
||||
unsigned int status_pad[3]; |
||||
unsigned int control; |
||||
unsigned int control_pad[3]; |
||||
unsigned int next_descriptor_pointer; |
||||
unsigned int descriptor_pad[3]; |
||||
}; |
||||
|
||||
/* TSE Stuff */ |
||||
#define ALTERA_TSE_CMD_TX_ENA_MSK (0x00000001) |
||||
#define ALTERA_TSE_CMD_RX_ENA_MSK (0x00000002) |
||||
#define ALTERA_TSE_CMD_XON_GEN_MSK (0x00000004) |
||||
#define ALTERA_TSE_CMD_ETH_SPEED_MSK (0x00000008) |
||||
#define ALTERA_TSE_CMD_PROMIS_EN_MSK (0x00000010) |
||||
#define ALTERA_TSE_CMD_PAD_EN_MSK (0x00000020) |
||||
#define ALTERA_TSE_CMD_CRC_FWD_MSK (0x00000040) |
||||
#define ALTERA_TSE_CMD_PAUSE_FWD_MSK (0x00000080) |
||||
#define ALTERA_TSE_CMD_PAUSE_IGNORE_MSK (0x00000100) |
||||
#define ALTERA_TSE_CMD_TX_ADDR_INS_MSK (0x00000200) |
||||
#define ALTERA_TSE_CMD_HD_ENA_MSK (0x00000400) |
||||
#define ALTERA_TSE_CMD_EXCESS_COL_MSK (0x00000800) |
||||
#define ALTERA_TSE_CMD_LATE_COL_MSK (0x00001000) |
||||
#define ALTERA_TSE_CMD_SW_RESET_MSK (0x00002000) |
||||
#define ALTERA_TSE_CMD_MHASH_SEL_MSK (0x00004000) |
||||
#define ALTERA_TSE_CMD_LOOPBACK_MSK (0x00008000) |
||||
/* Bits (18:16) = address select */ |
||||
#define ALTERA_TSE_CMD_TX_ADDR_SEL_MSK (0x00070000) |
||||
#define ALTERA_TSE_CMD_MAGIC_ENA_MSK (0x00080000) |
||||
#define ALTERA_TSE_CMD_SLEEP_MSK (0x00100000) |
||||
#define ALTERA_TSE_CMD_WAKEUP_MSK (0x00200000) |
||||
#define ALTERA_TSE_CMD_XOFF_GEN_MSK (0x00400000) |
||||
#define ALTERA_TSE_CMD_CNTL_FRM_ENA_MSK (0x00800000) |
||||
#define ALTERA_TSE_CMD_NO_LENGTH_CHECK_MSK (0x01000000) |
||||
#define ALTERA_TSE_CMD_ENA_10_MSK (0x02000000) |
||||
#define ALTERA_TSE_CMD_RX_ERR_DISC_MSK (0x04000000) |
||||
/* Bits (30..27) reserved */ |
||||
#define ALTERA_TSE_CMD_CNT_RESET_MSK (0x80000000) |
||||
|
||||
#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 (0x00040000) |
||||
#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC (0x00020000) |
||||
|
||||
#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16 (0x02000000) |
||||
|
||||
#define ALT_TSE_SW_RESET_WATCHDOG_CNTR 10000 |
||||
#define ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR 90000000 |
||||
|
||||
/* Command_Config Register Bit Definitions */ |
||||
|
||||
typedef volatile union __alt_tse_command_config { |
||||
unsigned int image; |
||||
struct { |
||||
unsigned int |
||||
transmit_enable:1, /* bit 0 */ |
||||
receive_enable:1, /* bit 1 */ |
||||
pause_frame_xon_gen:1, /* bit 2 */ |
||||
ethernet_speed:1, /* bit 3 */ |
||||
promiscuous_enable:1, /* bit 4 */ |
||||
pad_enable:1, /* bit 5 */ |
||||
crc_forward:1, /* bit 6 */ |
||||
pause_frame_forward:1, /* bit 7 */ |
||||
pause_frame_ignore:1, /* bit 8 */ |
||||
set_mac_address_on_tx:1, /* bit 9 */ |
||||
halfduplex_enable:1, /* bit 10 */ |
||||
excessive_collision:1, /* bit 11 */ |
||||
late_collision:1, /* bit 12 */ |
||||
software_reset:1, /* bit 13 */ |
||||
multicast_hash_mode_sel:1, /* bit 14 */ |
||||
loopback_enable:1, /* bit 15 */ |
||||
src_mac_addr_sel_on_tx:3, /* bit 18:16 */ |
||||
magic_packet_detect:1, /* bit 19 */ |
||||
sleep_mode_enable:1, /* bit 20 */ |
||||
wake_up_request:1, /* bit 21 */ |
||||
pause_frame_xoff_gen:1, /* bit 22 */ |
||||
control_frame_enable:1, /* bit 23 */ |
||||
payload_len_chk_disable:1, /* bit 24 */ |
||||
enable_10mbps_intf:1, /* bit 25 */ |
||||
rx_error_discard_enable:1, /* bit 26 */ |
||||
reserved_bits:4, /* bit 30:27 */ |
||||
self_clear_counter_reset:1; /* bit 31 */ |
||||
} __packed_1_ bits; |
||||
} __packed_1_ alt_tse_command_config; |
||||
|
||||
/* Tx_Cmd_Stat Register Bit Definitions */ |
||||
|
||||
typedef volatile union __alt_tse_tx_cmd_stat { |
||||
unsigned int image; |
||||
struct { |
||||
unsigned int reserved_lsbs:17, /* bit 16:0 */ |
||||
omit_crc:1, /* bit 17 */ |
||||
tx_shift16:1, /* bit 18 */ |
||||
reserved_msbs:13; /* bit 31:19 */ |
||||
|
||||
} __packed_1_ bits; |
||||
} alt_tse_tx_cmd_stat; |
||||
|
||||
/* Rx_Cmd_Stat Register Bit Definitions */ |
||||
|
||||
typedef volatile union __alt_tse_rx_cmd_stat { |
||||
unsigned int image; |
||||
struct { |
||||
unsigned int reserved_lsbs:25, /* bit 24:0 */ |
||||
rx_shift16:1, /* bit 25 */ |
||||
reserved_msbs:6; /* bit 31:26 */ |
||||
|
||||
} __packed_1_ bits; |
||||
} alt_tse_rx_cmd_stat; |
||||
|
||||
struct alt_tse_mdio { |
||||
unsigned int control; /*PHY device operation control register */ |
||||
unsigned int status; /*PHY device operation status register */ |
||||
unsigned int phy_id1; /*Bits 31:16 of PHY identifier. */ |
||||
unsigned int phy_id2; /*Bits 15:0 of PHY identifier. */ |
||||
unsigned int auto_negotiation_advertisement; |
||||
unsigned int remote_partner_base_page_ability; |
||||
|
||||
unsigned int reg6; |
||||
unsigned int reg7; |
||||
unsigned int reg8; |
||||
unsigned int reg9; |
||||
unsigned int rega; |
||||
unsigned int regb; |
||||
unsigned int regc; |
||||
unsigned int regd; |
||||
unsigned int rege; |
||||
unsigned int regf; |
||||
unsigned int reg10; |
||||
unsigned int reg11; |
||||
unsigned int reg12; |
||||
unsigned int reg13; |
||||
unsigned int reg14; |
||||
unsigned int reg15; |
||||
unsigned int reg16; |
||||
unsigned int reg17; |
||||
unsigned int reg18; |
||||
unsigned int reg19; |
||||
unsigned int reg1a; |
||||
unsigned int reg1b; |
||||
unsigned int reg1c; |
||||
unsigned int reg1d; |
||||
unsigned int reg1e; |
||||
unsigned int reg1f; |
||||
}; |
||||
|
||||
/* MAC register Space */ |
||||
|
||||
struct alt_tse_mac { |
||||
unsigned int megacore_revision; |
||||
unsigned int scratch_pad; |
||||
alt_tse_command_config command_config; |
||||
unsigned int mac_addr_0; |
||||
unsigned int mac_addr_1; |
||||
unsigned int max_frame_length; |
||||
unsigned int pause_quanta; |
||||
unsigned int rx_sel_empty_threshold; |
||||
unsigned int rx_sel_full_threshold; |
||||
unsigned int tx_sel_empty_threshold; |
||||
unsigned int tx_sel_full_threshold; |
||||
unsigned int rx_almost_empty_threshold; |
||||
unsigned int rx_almost_full_threshold; |
||||
unsigned int tx_almost_empty_threshold; |
||||
unsigned int tx_almost_full_threshold; |
||||
unsigned int mdio_phy0_addr; |
||||
unsigned int mdio_phy1_addr; |
||||
|
||||
/* only if 100/1000 BaseX PCS, reserved otherwise */ |
||||
unsigned int reservedx44[5]; |
||||
|
||||
unsigned int reg_read_access_status; |
||||
unsigned int min_tx_ipg_length; |
||||
|
||||
/* IEEE 802.3 oEntity Managed Object Support */ |
||||
unsigned int aMACID_1; /*The MAC addresses */ |
||||
unsigned int aMACID_2; |
||||
unsigned int aFramesTransmittedOK; |
||||
unsigned int aFramesReceivedOK; |
||||
unsigned int aFramesCheckSequenceErrors; |
||||
unsigned int aAlignmentErrors; |
||||
unsigned int aOctetsTransmittedOK; |
||||
unsigned int aOctetsReceivedOK; |
||||
|
||||
/* IEEE 802.3 oPausedEntity Managed Object Support */ |
||||
unsigned int aTxPAUSEMACCtrlFrames; |
||||
unsigned int aRxPAUSEMACCtrlFrames; |
||||
|
||||
/* IETF MIB (MIB-II) Object Support */ |
||||
unsigned int ifInErrors; |
||||
unsigned int ifOutErrors; |
||||
unsigned int ifInUcastPkts; |
||||
unsigned int ifInMulticastPkts; |
||||
unsigned int ifInBroadcastPkts; |
||||
unsigned int ifOutDiscards; |
||||
unsigned int ifOutUcastPkts; |
||||
unsigned int ifOutMulticastPkts; |
||||
unsigned int ifOutBroadcastPkts; |
||||
|
||||
/* IETF RMON MIB Object Support */ |
||||
unsigned int etherStatsDropEvent; |
||||
unsigned int etherStatsOctets; |
||||
unsigned int etherStatsPkts; |
||||
unsigned int etherStatsUndersizePkts; |
||||
unsigned int etherStatsOversizePkts; |
||||
unsigned int etherStatsPkts64Octets; |
||||
unsigned int etherStatsPkts65to127Octets; |
||||
unsigned int etherStatsPkts128to255Octets; |
||||
unsigned int etherStatsPkts256to511Octets; |
||||
unsigned int etherStatsPkts512to1023Octets; |
||||
unsigned int etherStatsPkts1024to1518Octets; |
||||
|
||||
unsigned int etherStatsPkts1519toXOctets; |
||||
unsigned int etherStatsJabbers; |
||||
unsigned int etherStatsFragments; |
||||
|
||||
unsigned int reservedxE4; |
||||
|
||||
/*FIFO control register. */ |
||||
alt_tse_tx_cmd_stat tx_cmd_stat; |
||||
alt_tse_rx_cmd_stat rx_cmd_stat; |
||||
|
||||
unsigned int ipaccTxConf; |
||||
unsigned int ipaccRxConf; |
||||
unsigned int ipaccRxStat; |
||||
unsigned int ipaccRxStatSum; |
||||
|
||||
/*Multicast address resolution table */ |
||||
unsigned int hash_table[64]; |
||||
|
||||
/*Registers 0 to 31 within PHY device 0/1 */ |
||||
struct alt_tse_mdio mdio_phy0; |
||||
struct alt_tse_mdio mdio_phy1; |
||||
|
||||
/*4 Supplemental MAC Addresses */ |
||||
unsigned int supp_mac_addr_0_0; |
||||
unsigned int supp_mac_addr_0_1; |
||||
unsigned int supp_mac_addr_1_0; |
||||
unsigned int supp_mac_addr_1_1; |
||||
unsigned int supp_mac_addr_2_0; |
||||
unsigned int supp_mac_addr_2_1; |
||||
unsigned int supp_mac_addr_3_0; |
||||
unsigned int supp_mac_addr_3_1; |
||||
|
||||
unsigned int reservedx320[56]; |
||||
}; |
||||
|
||||
/* flags: TSE MII modes */ |
||||
/* GMII/MII = 0 */ |
||||
/* RGMII = 1 */ |
||||
/* RGMII_ID = 2 */ |
||||
/* RGMII_TXID = 3 */ |
||||
/* RGMII_RXID = 4 */ |
||||
/* SGMII = 5 */ |
||||
struct altera_tse_priv { |
||||
char devname[16]; |
||||
volatile struct alt_tse_mac *mac_dev; |
||||
volatile struct alt_sgdma_registers *sgdma_rx; |
||||
volatile struct alt_sgdma_registers *sgdma_tx; |
||||
unsigned int rx_sgdma_irq; |
||||
unsigned int tx_sgdma_irq; |
||||
unsigned int has_descriptor_mem; |
||||
unsigned int descriptor_mem_base; |
||||
unsigned int descriptor_mem_size; |
||||
volatile struct alt_sgdma_descriptor *rx_desc; |
||||
volatile struct alt_sgdma_descriptor *tx_desc; |
||||
volatile unsigned char *rx_buf; |
||||
struct phy_info *phyinfo; |
||||
unsigned int phyaddr; |
||||
unsigned int flags; |
||||
unsigned int link; |
||||
unsigned int duplexity; |
||||
unsigned int speed; |
||||
}; |
||||
|
||||
/* Phy stuff continued */ |
||||
/*
|
||||
* struct phy_cmd: A command for reading or writing a PHY register |
||||
* |
||||
* mii_reg: The register to read or write |
||||
* |
||||
* mii_data: For writes, the value to put in the register. |
||||
* A value of -1 indicates this is a read. |
||||
* |
||||
* funct: A function pointer which is invoked for each command. |
||||
* For reads, this function will be passed the value read |
||||
* from the PHY, and process it. |
||||
* For writes, the result of this function will be written |
||||
* to the PHY register |
||||
*/ |
||||
struct phy_cmd { |
||||
uint mii_reg; |
||||
uint mii_data; |
||||
uint(*funct) (uint mii_reg, struct altera_tse_priv *priv); |
||||
}; |
||||
#endif /* _ALTERA_TSE_H_ */ |
Loading…
Reference in new issue