mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
ethernet: add gmac driver
This commit is contained in:
@@ -121,7 +121,7 @@
|
||||
};
|
||||
|
||||
vmac-phy {
|
||||
compatible = "vmac-phy";
|
||||
compatible = "rockchip,vmac-phy";
|
||||
power-gpios = <&gpio0 GPIO_C0 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@ config NET_VENDOR_ROCKCHIP
|
||||
|
||||
if NET_VENDOR_ROCKCHIP
|
||||
|
||||
source "drivers/net/ethernet/rk/vmac/Kconfig"
|
||||
source "drivers/net/ethernet/rockchip/vmac/Kconfig"
|
||||
source "drivers/net/ethernet/rockchip/gmac/Kconfig"
|
||||
|
||||
endif # NET_VENDOR_ROCKCHIP
|
||||
@@ -3,3 +3,4 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_RK_VMAC_ETH) += vmac/
|
||||
obj-$(CONFIG_RK_GMAC_ETH) += gmac/
|
||||
31
drivers/net/ethernet/rockchip/gmac/Kconfig
Executable file
31
drivers/net/ethernet/rockchip/gmac/Kconfig
Executable file
@@ -0,0 +1,31 @@
|
||||
config RK_GMAC_ETH
|
||||
tristate "Rockchip 10/100/1000 Ethernet driver"
|
||||
depends on HAS_IOMEM && HAS_DMA
|
||||
select NET_CORE
|
||||
select MII
|
||||
select PHYLIB
|
||||
select CRC32
|
||||
select PTP_1588_CLOCK
|
||||
---help---
|
||||
Rockchip 10/100/1000 Ethernet driver.
|
||||
|
||||
if RK_GMAC_ETH
|
||||
|
||||
config GMAC_DEBUG_FS
|
||||
bool "Enable monitoring via sysFS "
|
||||
default n
|
||||
depends on RK_GMAC_ETH && DEBUG_FS
|
||||
---help---
|
||||
The gmac entry in /sys reports DMA TX/RX rings
|
||||
or (if supported) the HW cap register.
|
||||
|
||||
config GMAC_DA
|
||||
bool "GMAC DMA arbitration scheme"
|
||||
default n
|
||||
---help---
|
||||
Selecting this option, rx has priority over Tx (only for Giga
|
||||
Ethernet device).
|
||||
By default, the DMA arbitration scheme is based on Round-robin
|
||||
(rx:tx priority is 1:1).
|
||||
|
||||
endif
|
||||
7
drivers/net/ethernet/rockchip/gmac/Makefile
Executable file
7
drivers/net/ethernet/rockchip/gmac/Makefile
Executable file
@@ -0,0 +1,7 @@
|
||||
obj-$(CONFIG_RK_GMAC_ETH) += stmmac.o
|
||||
stmmac-$(CONFIG_RK_GMAC_ETH) += stmmac_platform.o
|
||||
stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
|
||||
stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
|
||||
chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
|
||||
dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
|
||||
mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y)
|
||||
161
drivers/net/ethernet/rockchip/gmac/chain_mode.c
Executable file
161
drivers/net/ethernet/rockchip/gmac/chain_mode.c
Executable file
@@ -0,0 +1,161 @@
|
||||
/*******************************************************************************
|
||||
Specialised functions for managing Chained mode
|
||||
|
||||
Copyright(C) 2011 STMicroelectronics Ltd
|
||||
|
||||
It defines all the functions used to handle the normal/enhanced
|
||||
descriptors in case of the DMA is configured to work in chained or
|
||||
in ring mode.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include "stmmac.h"
|
||||
|
||||
static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)p;
|
||||
unsigned int txsize = priv->dma_tx_size;
|
||||
unsigned int entry = priv->cur_tx % txsize;
|
||||
struct dma_desc *desc = priv->dma_tx + entry;
|
||||
unsigned int nopaged_len = skb_headlen(skb);
|
||||
unsigned int bmax;
|
||||
unsigned int i = 1, len;
|
||||
|
||||
if (priv->plat->enh_desc)
|
||||
bmax = BUF_SIZE_8KiB;
|
||||
else
|
||||
bmax = BUF_SIZE_2KiB;
|
||||
|
||||
len = nopaged_len - bmax;
|
||||
|
||||
desc->des2 = dma_map_single(priv->device, skb->data,
|
||||
bmax, DMA_TO_DEVICE);
|
||||
priv->tx_skbuff_dma[entry] = desc->des2;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);
|
||||
|
||||
while (len != 0) {
|
||||
entry = (++priv->cur_tx) % txsize;
|
||||
desc = priv->dma_tx + entry;
|
||||
|
||||
if (len > bmax) {
|
||||
desc->des2 = dma_map_single(priv->device,
|
||||
(skb->data + bmax * i),
|
||||
bmax, DMA_TO_DEVICE);
|
||||
priv->tx_skbuff_dma[entry] = desc->des2;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
|
||||
STMMAC_CHAIN_MODE);
|
||||
priv->hw->desc->set_tx_owner(desc);
|
||||
priv->tx_skbuff[entry] = NULL;
|
||||
len -= bmax;
|
||||
i++;
|
||||
} else {
|
||||
desc->des2 = dma_map_single(priv->device,
|
||||
(skb->data + bmax * i), len,
|
||||
DMA_TO_DEVICE);
|
||||
priv->tx_skbuff_dma[entry] = desc->des2;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
|
||||
STMMAC_CHAIN_MODE);
|
||||
priv->hw->desc->set_tx_owner(desc);
|
||||
priv->tx_skbuff[entry] = NULL;
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if ((enh_desc && (len > BUF_SIZE_8KiB)) ||
|
||||
(!enh_desc && (len > BUF_SIZE_2KiB))) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stmmac_init_dma_chain(void *des, dma_addr_t phy_addr,
|
||||
unsigned int size, unsigned int extend_desc)
|
||||
{
|
||||
/*
|
||||
* In chained mode the des3 points to the next element in the ring.
|
||||
* The latest element has to point to the head.
|
||||
*/
|
||||
int i;
|
||||
dma_addr_t dma_phy = phy_addr;
|
||||
|
||||
if (extend_desc) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)des;
|
||||
for (i = 0; i < (size - 1); i++) {
|
||||
dma_phy += sizeof(struct dma_extended_desc);
|
||||
p->basic.des3 = (unsigned int)dma_phy;
|
||||
p++;
|
||||
}
|
||||
p->basic.des3 = (unsigned int)phy_addr;
|
||||
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)des;
|
||||
for (i = 0; i < (size - 1); i++) {
|
||||
dma_phy += sizeof(struct dma_desc);
|
||||
p->des3 = (unsigned int)dma_phy;
|
||||
p++;
|
||||
}
|
||||
p->des3 = (unsigned int)phy_addr;
|
||||
}
|
||||
}
|
||||
|
||||
static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
|
||||
|
||||
if (priv->hwts_rx_en && !priv->extend_desc)
|
||||
/* NOTE: Device will overwrite des3 with timestamp value if
|
||||
* 1588-2002 time stamping is enabled, hence reinitialize it
|
||||
* to keep explicit chaining in the descriptor.
|
||||
*/
|
||||
p->des3 = (unsigned int)(priv->dma_rx_phy +
|
||||
(((priv->dirty_rx) + 1) %
|
||||
priv->dma_rx_size) *
|
||||
sizeof(struct dma_desc));
|
||||
}
|
||||
|
||||
static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
|
||||
|
||||
if (priv->hw->desc->get_tx_ls(p) && !priv->extend_desc)
|
||||
/* NOTE: Device will overwrite des3 with timestamp value if
|
||||
* 1588-2002 time stamping is enabled, hence reinitialize it
|
||||
* to keep explicit chaining in the descriptor.
|
||||
*/
|
||||
p->des3 = (unsigned int)(priv->dma_tx_phy +
|
||||
(((priv->dirty_tx + 1) %
|
||||
priv->dma_tx_size) *
|
||||
sizeof(struct dma_desc)));
|
||||
}
|
||||
|
||||
const struct stmmac_chain_mode_ops chain_mode_ops = {
|
||||
.init = stmmac_init_dma_chain,
|
||||
.is_jumbo_frm = stmmac_is_jumbo_frm,
|
||||
.jumbo_frm = stmmac_jumbo_frm,
|
||||
.refill_desc3 = stmmac_refill_desc3,
|
||||
.clean_desc3 = stmmac_clean_desc3,
|
||||
};
|
||||
475
drivers/net/ethernet/rockchip/gmac/common.h
Executable file
475
drivers/net/ethernet/rockchip/gmac/common.h
Executable file
@@ -0,0 +1,475 @@
|
||||
/*******************************************************************************
|
||||
STMMAC Common Header File
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __COMMON_H__
|
||||
#define __COMMON_H__
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
|
||||
#define STMMAC_VLAN_TAG_USED
|
||||
#include <linux/if_vlan.h>
|
||||
#endif
|
||||
|
||||
#include "descs.h"
|
||||
#include "mmc.h"
|
||||
|
||||
#undef CHIP_DEBUG_PRINT
|
||||
/* Turn-on extra printk debug for MAC core, dma and descriptors */
|
||||
/* #define CHIP_DEBUG_PRINT */
|
||||
|
||||
#ifdef CHIP_DEBUG_PRINT
|
||||
#define CHIP_DBG(fmt, args...) printk(fmt, ## args)
|
||||
#else
|
||||
#define CHIP_DBG(fmt, args...) do { } while (0)
|
||||
#endif
|
||||
|
||||
/* Synopsys Core versions */
|
||||
#define DWMAC_CORE_3_40 0x34
|
||||
#define DWMAC_CORE_3_50 0x35
|
||||
|
||||
#undef FRAME_FILTER_DEBUG
|
||||
/* #define FRAME_FILTER_DEBUG */
|
||||
|
||||
struct stmmac_extra_stats {
|
||||
/* Transmit errors */
|
||||
unsigned long tx_underflow ____cacheline_aligned;
|
||||
unsigned long tx_carrier;
|
||||
unsigned long tx_losscarrier;
|
||||
unsigned long vlan_tag;
|
||||
unsigned long tx_deferred;
|
||||
unsigned long tx_vlan;
|
||||
unsigned long tx_jabber;
|
||||
unsigned long tx_frame_flushed;
|
||||
unsigned long tx_payload_error;
|
||||
unsigned long tx_ip_header_error;
|
||||
/* Receive errors */
|
||||
unsigned long rx_desc;
|
||||
unsigned long sa_filter_fail;
|
||||
unsigned long overflow_error;
|
||||
unsigned long ipc_csum_error;
|
||||
unsigned long rx_collision;
|
||||
unsigned long rx_crc;
|
||||
unsigned long dribbling_bit;
|
||||
unsigned long rx_length;
|
||||
unsigned long rx_mii;
|
||||
unsigned long rx_multicast;
|
||||
unsigned long rx_gmac_overflow;
|
||||
unsigned long rx_watchdog;
|
||||
unsigned long da_rx_filter_fail;
|
||||
unsigned long sa_rx_filter_fail;
|
||||
unsigned long rx_missed_cntr;
|
||||
unsigned long rx_overflow_cntr;
|
||||
unsigned long rx_vlan;
|
||||
/* Tx/Rx IRQ error info */
|
||||
unsigned long tx_undeflow_irq;
|
||||
unsigned long tx_process_stopped_irq;
|
||||
unsigned long tx_jabber_irq;
|
||||
unsigned long rx_overflow_irq;
|
||||
unsigned long rx_buf_unav_irq;
|
||||
unsigned long rx_process_stopped_irq;
|
||||
unsigned long rx_watchdog_irq;
|
||||
unsigned long tx_early_irq;
|
||||
unsigned long fatal_bus_error_irq;
|
||||
/* Tx/Rx IRQ Events */
|
||||
unsigned long rx_early_irq;
|
||||
unsigned long threshold;
|
||||
unsigned long tx_pkt_n;
|
||||
unsigned long rx_pkt_n;
|
||||
unsigned long normal_irq_n;
|
||||
unsigned long rx_normal_irq_n;
|
||||
unsigned long napi_poll;
|
||||
unsigned long tx_normal_irq_n;
|
||||
unsigned long tx_clean;
|
||||
unsigned long tx_reset_ic_bit;
|
||||
unsigned long irq_receive_pmt_irq_n;
|
||||
/* MMC info */
|
||||
unsigned long mmc_tx_irq_n;
|
||||
unsigned long mmc_rx_irq_n;
|
||||
unsigned long mmc_rx_csum_offload_irq_n;
|
||||
/* EEE */
|
||||
unsigned long irq_tx_path_in_lpi_mode_n;
|
||||
unsigned long irq_tx_path_exit_lpi_mode_n;
|
||||
unsigned long irq_rx_path_in_lpi_mode_n;
|
||||
unsigned long irq_rx_path_exit_lpi_mode_n;
|
||||
unsigned long phy_eee_wakeup_error_n;
|
||||
/* Extended RDES status */
|
||||
unsigned long ip_hdr_err;
|
||||
unsigned long ip_payload_err;
|
||||
unsigned long ip_csum_bypassed;
|
||||
unsigned long ipv4_pkt_rcvd;
|
||||
unsigned long ipv6_pkt_rcvd;
|
||||
unsigned long rx_msg_type_ext_no_ptp;
|
||||
unsigned long rx_msg_type_sync;
|
||||
unsigned long rx_msg_type_follow_up;
|
||||
unsigned long rx_msg_type_delay_req;
|
||||
unsigned long rx_msg_type_delay_resp;
|
||||
unsigned long rx_msg_type_pdelay_req;
|
||||
unsigned long rx_msg_type_pdelay_resp;
|
||||
unsigned long rx_msg_type_pdelay_follow_up;
|
||||
unsigned long ptp_frame_type;
|
||||
unsigned long ptp_ver;
|
||||
unsigned long timestamp_dropped;
|
||||
unsigned long av_pkt_rcvd;
|
||||
unsigned long av_tagged_pkt_rcvd;
|
||||
unsigned long vlan_tag_priority_val;
|
||||
unsigned long l3_filter_match;
|
||||
unsigned long l4_filter_match;
|
||||
unsigned long l3_l4_filter_no_match;
|
||||
/* PCS */
|
||||
unsigned long irq_pcs_ane_n;
|
||||
unsigned long irq_pcs_link_n;
|
||||
unsigned long irq_rgmii_n;
|
||||
unsigned long pcs_link;
|
||||
unsigned long pcs_duplex;
|
||||
unsigned long pcs_speed;
|
||||
};
|
||||
|
||||
/* CSR Frequency Access Defines*/
|
||||
#define CSR_F_35M 35000000
|
||||
#define CSR_F_60M 60000000
|
||||
#define CSR_F_100M 100000000
|
||||
#define CSR_F_150M 150000000
|
||||
#define CSR_F_250M 250000000
|
||||
#define CSR_F_300M 300000000
|
||||
|
||||
#define MAC_CSR_H_FRQ_MASK 0x20
|
||||
|
||||
#define HASH_TABLE_SIZE 64
|
||||
#define PAUSE_TIME 0x200
|
||||
|
||||
/* Flow Control defines */
|
||||
#define FLOW_OFF 0
|
||||
#define FLOW_RX 1
|
||||
#define FLOW_TX 2
|
||||
#define FLOW_AUTO (FLOW_TX | FLOW_RX)
|
||||
|
||||
/* PCS defines */
|
||||
#define STMMAC_PCS_RGMII (1 << 0)
|
||||
#define STMMAC_PCS_SGMII (1 << 1)
|
||||
#define STMMAC_PCS_TBI (1 << 2)
|
||||
#define STMMAC_PCS_RTBI (1 << 3)
|
||||
|
||||
#define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */
|
||||
|
||||
/* DAM HW feature register fields */
|
||||
#define DMA_HW_FEAT_MIISEL 0x00000001 /* 10/100 Mbps Support */
|
||||
#define DMA_HW_FEAT_GMIISEL 0x00000002 /* 1000 Mbps Support */
|
||||
#define DMA_HW_FEAT_HDSEL 0x00000004 /* Half-Duplex Support */
|
||||
#define DMA_HW_FEAT_EXTHASHEN 0x00000008 /* Expanded DA Hash Filter */
|
||||
#define DMA_HW_FEAT_HASHSEL 0x00000010 /* HASH Filter */
|
||||
#define DMA_HW_FEAT_ADDMAC 0x00000020 /* Multiple MAC Addr Reg */
|
||||
#define DMA_HW_FEAT_PCSSEL 0x00000040 /* PCS registers */
|
||||
#define DMA_HW_FEAT_L3L4FLTREN 0x00000080 /* Layer 3 & Layer 4 Feature */
|
||||
#define DMA_HW_FEAT_SMASEL 0x00000100 /* SMA(MDIO) Interface */
|
||||
#define DMA_HW_FEAT_RWKSEL 0x00000200 /* PMT Remote Wakeup */
|
||||
#define DMA_HW_FEAT_MGKSEL 0x00000400 /* PMT Magic Packet */
|
||||
#define DMA_HW_FEAT_MMCSEL 0x00000800 /* RMON Module */
|
||||
#define DMA_HW_FEAT_TSVER1SEL 0x00001000 /* Only IEEE 1588-2002 */
|
||||
#define DMA_HW_FEAT_TSVER2SEL 0x00002000 /* IEEE 1588-2008 PTPv2 */
|
||||
#define DMA_HW_FEAT_EEESEL 0x00004000 /* Energy Efficient Ethernet */
|
||||
#define DMA_HW_FEAT_AVSEL 0x00008000 /* AV Feature */
|
||||
#define DMA_HW_FEAT_TXCOESEL 0x00010000 /* Checksum Offload in Tx */
|
||||
#define DMA_HW_FEAT_RXTYP1COE 0x00020000 /* IP COE (Type 1) in Rx */
|
||||
#define DMA_HW_FEAT_RXTYP2COE 0x00040000 /* IP COE (Type 2) in Rx */
|
||||
#define DMA_HW_FEAT_RXFIFOSIZE 0x00080000 /* Rx FIFO > 2048 Bytes */
|
||||
#define DMA_HW_FEAT_RXCHCNT 0x00300000 /* No. additional Rx Channels */
|
||||
#define DMA_HW_FEAT_TXCHCNT 0x00c00000 /* No. additional Tx Channels */
|
||||
#define DMA_HW_FEAT_ENHDESSEL 0x01000000 /* Alternate Descriptor */
|
||||
/* Timestamping with Internal System Time */
|
||||
#define DMA_HW_FEAT_INTTSEN 0x02000000
|
||||
#define DMA_HW_FEAT_FLEXIPPSEN 0x04000000 /* Flexible PPS Output */
|
||||
#define DMA_HW_FEAT_SAVLANINS 0x08000000 /* Source Addr or VLAN */
|
||||
#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY iface */
|
||||
#define DEFAULT_DMA_PBL 8
|
||||
|
||||
/* Max/Min RI Watchdog Timer count value */
|
||||
#define MAX_DMA_RIWT 0xff
|
||||
#define MIN_DMA_RIWT 0x20
|
||||
/* Tx coalesce parameters */
|
||||
#define STMMAC_COAL_TX_TIMER 40000
|
||||
#define STMMAC_MAX_COAL_TX_TICK 100000
|
||||
#define STMMAC_TX_MAX_FRAMES 256
|
||||
#define STMMAC_TX_FRAMES 64
|
||||
|
||||
/* Rx IPC status */
|
||||
enum rx_frame_status {
|
||||
good_frame = 0,
|
||||
discard_frame = 1,
|
||||
csum_none = 2,
|
||||
llc_snap = 4,
|
||||
};
|
||||
|
||||
enum dma_irq_status {
|
||||
tx_hard_error = 0x1,
|
||||
tx_hard_error_bump_tc = 0x2,
|
||||
handle_rx = 0x4,
|
||||
handle_tx = 0x8,
|
||||
};
|
||||
|
||||
#define CORE_IRQ_TX_PATH_IN_LPI_MODE (1 << 1)
|
||||
#define CORE_IRQ_TX_PATH_EXIT_LPI_MODE (1 << 2)
|
||||
#define CORE_IRQ_RX_PATH_IN_LPI_MODE (1 << 3)
|
||||
#define CORE_IRQ_RX_PATH_EXIT_LPI_MODE (1 << 4)
|
||||
|
||||
#define CORE_PCS_ANE_COMPLETE (1 << 5)
|
||||
#define CORE_PCS_LINK_STATUS (1 << 6)
|
||||
#define CORE_RGMII_IRQ (1 << 7)
|
||||
|
||||
struct rgmii_adv {
|
||||
unsigned int pause;
|
||||
unsigned int duplex;
|
||||
unsigned int lp_pause;
|
||||
unsigned int lp_duplex;
|
||||
};
|
||||
|
||||
#define STMMAC_PCS_PAUSE 1
|
||||
#define STMMAC_PCS_ASYM_PAUSE 2
|
||||
|
||||
/* DMA HW capabilities */
|
||||
struct dma_features {
|
||||
unsigned int mbps_10_100;
|
||||
unsigned int mbps_1000;
|
||||
unsigned int half_duplex;
|
||||
unsigned int hash_filter;
|
||||
unsigned int multi_addr;
|
||||
unsigned int pcs;
|
||||
unsigned int sma_mdio;
|
||||
unsigned int pmt_remote_wake_up;
|
||||
unsigned int pmt_magic_frame;
|
||||
unsigned int rmon;
|
||||
/* IEEE 1588-2002 */
|
||||
unsigned int time_stamp;
|
||||
/* IEEE 1588-2008 */
|
||||
unsigned int atime_stamp;
|
||||
/* 802.3az - Energy-Efficient Ethernet (EEE) */
|
||||
unsigned int eee;
|
||||
unsigned int av;
|
||||
/* TX and RX csum */
|
||||
unsigned int tx_coe;
|
||||
unsigned int rx_coe_type1;
|
||||
unsigned int rx_coe_type2;
|
||||
unsigned int rxfifo_over_2048;
|
||||
/* TX and RX number of channels */
|
||||
unsigned int number_rx_channel;
|
||||
unsigned int number_tx_channel;
|
||||
/* Alternate (enhanced) DESC mode */
|
||||
unsigned int enh_desc;
|
||||
};
|
||||
|
||||
/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
|
||||
#define BUF_SIZE_16KiB 16384
|
||||
#define BUF_SIZE_8KiB 8192
|
||||
#define BUF_SIZE_4KiB 4096
|
||||
#define BUF_SIZE_2KiB 2048
|
||||
|
||||
/* Power Down and WOL */
|
||||
#define PMT_NOT_SUPPORTED 0
|
||||
#define PMT_SUPPORTED 1
|
||||
|
||||
/* Common MAC defines */
|
||||
#define MAC_CTRL_REG 0x00000000 /* MAC Control */
|
||||
#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
|
||||
#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */
|
||||
|
||||
/* Default LPI timers */
|
||||
#define STMMAC_DEFAULT_LIT_LS 0x3E8
|
||||
#define STMMAC_DEFAULT_TWT_LS 0x0
|
||||
|
||||
#define STMMAC_CHAIN_MODE 0x1
|
||||
#define STMMAC_RING_MODE 0x2
|
||||
|
||||
struct stmmac_desc_ops {
|
||||
/* DMA RX descriptor ring initialization */
|
||||
void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode,
|
||||
int end);
|
||||
/* DMA TX descriptor ring initialization */
|
||||
void (*init_tx_desc) (struct dma_desc *p, int mode, int end);
|
||||
|
||||
/* Invoked by the xmit function to prepare the tx descriptor */
|
||||
void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len,
|
||||
int csum_flag, int mode);
|
||||
/* Set/get the owner of the descriptor */
|
||||
void (*set_tx_owner) (struct dma_desc *p);
|
||||
int (*get_tx_owner) (struct dma_desc *p);
|
||||
/* Invoked by the xmit function to close the tx descriptor */
|
||||
void (*close_tx_desc) (struct dma_desc *p);
|
||||
/* Clean the tx descriptor as soon as the tx irq is received */
|
||||
void (*release_tx_desc) (struct dma_desc *p, int mode);
|
||||
/* Clear interrupt on tx frame completion. When this bit is
|
||||
* set an interrupt happens as soon as the frame is transmitted */
|
||||
void (*clear_tx_ic) (struct dma_desc *p);
|
||||
/* Last tx segment reports the transmit status */
|
||||
int (*get_tx_ls) (struct dma_desc *p);
|
||||
/* Return the transmit status looking at the TDES1 */
|
||||
int (*tx_status) (void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr);
|
||||
/* Get the buffer size from the descriptor */
|
||||
int (*get_tx_len) (struct dma_desc *p);
|
||||
/* Handle extra events on specific interrupts hw dependent */
|
||||
int (*get_rx_owner) (struct dma_desc *p);
|
||||
void (*set_rx_owner) (struct dma_desc *p);
|
||||
/* Get the receive frame size */
|
||||
int (*get_rx_frame_len) (struct dma_desc *p, int rx_coe_type);
|
||||
/* Return the reception status looking at the RDES1 */
|
||||
int (*rx_status) (void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p);
|
||||
void (*rx_extended_status) (void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_extended_desc *p);
|
||||
/* Set tx timestamp enable bit */
|
||||
void (*enable_tx_timestamp) (struct dma_desc *p);
|
||||
/* get tx timestamp status */
|
||||
int (*get_tx_timestamp_status) (struct dma_desc *p);
|
||||
/* get timestamp value */
|
||||
u64(*get_timestamp) (void *desc, u32 ats);
|
||||
/* get rx timestamp status */
|
||||
int (*get_rx_timestamp_status) (void *desc, u32 ats);
|
||||
};
|
||||
|
||||
struct stmmac_dma_ops {
|
||||
/* DMA core initialization */
|
||||
int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
|
||||
int burst_len, u32 dma_tx, u32 dma_rx, int atds);
|
||||
/* Dump DMA registers */
|
||||
void (*dump_regs) (void __iomem *ioaddr);
|
||||
/* Set tx/rx threshold in the csr6 register
|
||||
* An invalid value enables the store-and-forward mode */
|
||||
void (*dma_mode) (void __iomem *ioaddr, int txmode, int rxmode);
|
||||
/* To track extra statistic (if supported) */
|
||||
void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr);
|
||||
void (*enable_dma_transmission) (void __iomem *ioaddr);
|
||||
void (*enable_dma_irq) (void __iomem *ioaddr);
|
||||
void (*disable_dma_irq) (void __iomem *ioaddr);
|
||||
void (*start_tx) (void __iomem *ioaddr);
|
||||
void (*stop_tx) (void __iomem *ioaddr);
|
||||
void (*start_rx) (void __iomem *ioaddr);
|
||||
void (*stop_rx) (void __iomem *ioaddr);
|
||||
int (*dma_interrupt) (void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x);
|
||||
/* If supported then get the optional core features */
|
||||
unsigned int (*get_hw_feature) (void __iomem *ioaddr);
|
||||
/* Program the HW RX Watchdog */
|
||||
void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt);
|
||||
};
|
||||
|
||||
struct stmmac_ops {
|
||||
/* MAC core initialization */
|
||||
void (*core_init) (void __iomem *ioaddr);
|
||||
/* Enable and verify that the IPC module is supported */
|
||||
int (*rx_ipc) (void __iomem *ioaddr);
|
||||
/* Dump MAC registers */
|
||||
void (*dump_regs) (void __iomem *ioaddr);
|
||||
/* Handle extra events on specific interrupts hw dependent */
|
||||
int (*host_irq_status) (void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x);
|
||||
/* Multicast filter setting */
|
||||
void (*set_filter) (struct net_device *dev, int id);
|
||||
/* Flow control setting */
|
||||
void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time);
|
||||
/* Set power management mode (e.g. magic frame) */
|
||||
void (*pmt) (void __iomem *ioaddr, unsigned long mode);
|
||||
/* Set/Get Unicast MAC addresses */
|
||||
void (*set_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int reg_n);
|
||||
void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int reg_n);
|
||||
void (*set_eee_mode) (void __iomem *ioaddr);
|
||||
void (*reset_eee_mode) (void __iomem *ioaddr);
|
||||
void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
|
||||
void (*set_eee_pls) (void __iomem *ioaddr, int link);
|
||||
void (*ctrl_ane) (void __iomem *ioaddr, bool restart);
|
||||
void (*get_adv) (void __iomem *ioaddr, struct rgmii_adv *adv);
|
||||
};
|
||||
|
||||
struct stmmac_hwtimestamp {
|
||||
void (*config_hw_tstamping) (void __iomem *ioaddr, u32 data);
|
||||
void (*config_sub_second_increment) (void __iomem *ioaddr);
|
||||
int (*init_systime) (void __iomem *ioaddr, u32 sec, u32 nsec);
|
||||
int (*config_addend) (void __iomem *ioaddr, u32 addend);
|
||||
int (*adjust_systime) (void __iomem *ioaddr, u32 sec, u32 nsec,
|
||||
int add_sub);
|
||||
u64(*get_systime) (void __iomem *ioaddr);
|
||||
};
|
||||
|
||||
struct mac_link {
|
||||
int port;
|
||||
int duplex;
|
||||
int speed;
|
||||
};
|
||||
|
||||
struct mii_regs {
|
||||
unsigned int addr; /* MII Address */
|
||||
unsigned int data; /* MII Data */
|
||||
};
|
||||
|
||||
struct stmmac_ring_mode_ops {
|
||||
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
|
||||
unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
|
||||
void (*refill_desc3) (void *priv, struct dma_desc *p);
|
||||
void (*init_desc3) (struct dma_desc *p);
|
||||
void (*clean_desc3) (void *priv, struct dma_desc *p);
|
||||
int (*set_16kib_bfsize) (int mtu);
|
||||
};
|
||||
|
||||
struct stmmac_chain_mode_ops {
|
||||
void (*init) (void *des, dma_addr_t phy_addr, unsigned int size,
|
||||
unsigned int extend_desc);
|
||||
unsigned int (*is_jumbo_frm) (int len, int ehn_desc);
|
||||
unsigned int (*jumbo_frm) (void *priv, struct sk_buff *skb, int csum);
|
||||
void (*refill_desc3) (void *priv, struct dma_desc *p);
|
||||
void (*clean_desc3) (void *priv, struct dma_desc *p);
|
||||
};
|
||||
|
||||
struct mac_device_info {
|
||||
const struct stmmac_ops *mac;
|
||||
const struct stmmac_desc_ops *desc;
|
||||
const struct stmmac_dma_ops *dma;
|
||||
const struct stmmac_ring_mode_ops *ring;
|
||||
const struct stmmac_chain_mode_ops *chain;
|
||||
const struct stmmac_hwtimestamp *ptp;
|
||||
struct mii_regs mii; /* MII register Addresses */
|
||||
struct mac_link link;
|
||||
unsigned int synopsys_uid;
|
||||
};
|
||||
|
||||
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr);
|
||||
struct mac_device_info *dwmac100_setup(void __iomem *ioaddr);
|
||||
|
||||
extern void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
|
||||
unsigned int high, unsigned int low);
|
||||
extern void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low);
|
||||
|
||||
extern void stmmac_set_mac(void __iomem *ioaddr, bool enable);
|
||||
|
||||
extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
|
||||
extern const struct stmmac_ring_mode_ops ring_mode_ops;
|
||||
extern const struct stmmac_chain_mode_ops chain_mode_ops;
|
||||
|
||||
#endif /* __COMMON_H__ */
|
||||
219
drivers/net/ethernet/rockchip/gmac/descs.h
Executable file
219
drivers/net/ethernet/rockchip/gmac/descs.h
Executable file
@@ -0,0 +1,219 @@
|
||||
/*******************************************************************************
|
||||
Header File to describe the DMA descriptors.
|
||||
Enhanced descriptors have been in case of DWMAC1000 Cores.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESCS_H__
|
||||
#define __DESCS_H__
|
||||
|
||||
/* Basic descriptor structure for normal and alternate descriptors */
|
||||
struct dma_desc {
|
||||
/* Receive descriptor */
|
||||
union {
|
||||
struct {
|
||||
/* RDES0 */
|
||||
u32 payload_csum_error:1;
|
||||
u32 crc_error:1;
|
||||
u32 dribbling:1;
|
||||
u32 mii_error:1;
|
||||
u32 receive_watchdog:1;
|
||||
u32 frame_type:1;
|
||||
u32 collision:1;
|
||||
u32 ipc_csum_error:1;
|
||||
u32 last_descriptor:1;
|
||||
u32 first_descriptor:1;
|
||||
u32 vlan_tag:1;
|
||||
u32 overflow_error:1;
|
||||
u32 length_error:1;
|
||||
u32 sa_filter_fail:1;
|
||||
u32 descriptor_error:1;
|
||||
u32 error_summary:1;
|
||||
u32 frame_length:14;
|
||||
u32 da_filter_fail:1;
|
||||
u32 own:1;
|
||||
/* RDES1 */
|
||||
u32 buffer1_size:11;
|
||||
u32 buffer2_size:11;
|
||||
u32 reserved1:2;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 reserved2:5;
|
||||
u32 disable_ic:1;
|
||||
|
||||
} rx;
|
||||
struct {
|
||||
/* RDES0 */
|
||||
u32 rx_mac_addr:1;
|
||||
u32 crc_error:1;
|
||||
u32 dribbling:1;
|
||||
u32 error_gmii:1;
|
||||
u32 receive_watchdog:1;
|
||||
u32 frame_type:1;
|
||||
u32 late_collision:1;
|
||||
u32 ipc_csum_error:1;
|
||||
u32 last_descriptor:1;
|
||||
u32 first_descriptor:1;
|
||||
u32 vlan_tag:1;
|
||||
u32 overflow_error:1;
|
||||
u32 length_error:1;
|
||||
u32 sa_filter_fail:1;
|
||||
u32 descriptor_error:1;
|
||||
u32 error_summary:1;
|
||||
u32 frame_length:14;
|
||||
u32 da_filter_fail:1;
|
||||
u32 own:1;
|
||||
/* RDES1 */
|
||||
u32 buffer1_size:13;
|
||||
u32 reserved1:1;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 buffer2_size:13;
|
||||
u32 reserved2:2;
|
||||
u32 disable_ic:1;
|
||||
} erx; /* -- enhanced -- */
|
||||
|
||||
/* Transmit descriptor */
|
||||
struct {
|
||||
/* TDES0 */
|
||||
u32 deferred:1;
|
||||
u32 underflow_error:1;
|
||||
u32 excessive_deferral:1;
|
||||
u32 collision_count:4;
|
||||
u32 vlan_frame:1;
|
||||
u32 excessive_collisions:1;
|
||||
u32 late_collision:1;
|
||||
u32 no_carrier:1;
|
||||
u32 loss_carrier:1;
|
||||
u32 payload_error:1;
|
||||
u32 frame_flushed:1;
|
||||
u32 jabber_timeout:1;
|
||||
u32 error_summary:1;
|
||||
u32 ip_header_error:1;
|
||||
u32 time_stamp_status:1;
|
||||
u32 reserved1:13;
|
||||
u32 own:1;
|
||||
/* TDES1 */
|
||||
u32 buffer1_size:11;
|
||||
u32 buffer2_size:11;
|
||||
u32 time_stamp_enable:1;
|
||||
u32 disable_padding:1;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 crc_disable:1;
|
||||
u32 checksum_insertion:2;
|
||||
u32 first_segment:1;
|
||||
u32 last_segment:1;
|
||||
u32 interrupt:1;
|
||||
} tx;
|
||||
struct {
|
||||
/* TDES0 */
|
||||
u32 deferred:1;
|
||||
u32 underflow_error:1;
|
||||
u32 excessive_deferral:1;
|
||||
u32 collision_count:4;
|
||||
u32 vlan_frame:1;
|
||||
u32 excessive_collisions:1;
|
||||
u32 late_collision:1;
|
||||
u32 no_carrier:1;
|
||||
u32 loss_carrier:1;
|
||||
u32 payload_error:1;
|
||||
u32 frame_flushed:1;
|
||||
u32 jabber_timeout:1;
|
||||
u32 error_summary:1;
|
||||
u32 ip_header_error:1;
|
||||
u32 time_stamp_status:1;
|
||||
u32 reserved1:2;
|
||||
u32 second_address_chained:1;
|
||||
u32 end_ring:1;
|
||||
u32 checksum_insertion:2;
|
||||
u32 reserved2:1;
|
||||
u32 time_stamp_enable:1;
|
||||
u32 disable_padding:1;
|
||||
u32 crc_disable:1;
|
||||
u32 first_segment:1;
|
||||
u32 last_segment:1;
|
||||
u32 interrupt:1;
|
||||
u32 own:1;
|
||||
/* TDES1 */
|
||||
u32 buffer1_size:13;
|
||||
u32 reserved3:3;
|
||||
u32 buffer2_size:13;
|
||||
u32 reserved4:3;
|
||||
} etx; /* -- enhanced -- */
|
||||
} des01;
|
||||
unsigned int des2;
|
||||
unsigned int des3;
|
||||
};
|
||||
|
||||
/* Extended descriptor structure (supported by new SYNP GMAC generations) */
|
||||
struct dma_extended_desc {
|
||||
struct dma_desc basic;
|
||||
union {
|
||||
struct {
|
||||
u32 ip_payload_type:3;
|
||||
u32 ip_hdr_err:1;
|
||||
u32 ip_payload_err:1;
|
||||
u32 ip_csum_bypassed:1;
|
||||
u32 ipv4_pkt_rcvd:1;
|
||||
u32 ipv6_pkt_rcvd:1;
|
||||
u32 msg_type:4;
|
||||
u32 ptp_frame_type:1;
|
||||
u32 ptp_ver:1;
|
||||
u32 timestamp_dropped:1;
|
||||
u32 reserved:1;
|
||||
u32 av_pkt_rcvd:1;
|
||||
u32 av_tagged_pkt_rcvd:1;
|
||||
u32 vlan_tag_priority_val:3;
|
||||
u32 reserved3:3;
|
||||
u32 l3_filter_match:1;
|
||||
u32 l4_filter_match:1;
|
||||
u32 l3_l4_filter_no_match:2;
|
||||
u32 reserved4:4;
|
||||
} erx;
|
||||
struct {
|
||||
u32 reserved;
|
||||
} etx;
|
||||
} des4;
|
||||
unsigned int des5; /* Reserved */
|
||||
unsigned int des6; /* Tx/Rx Timestamp Low */
|
||||
unsigned int des7; /* Tx/Rx Timestamp High */
|
||||
};
|
||||
|
||||
/* Transmit checksum insertion control */
|
||||
enum tdes_csum_insertion {
|
||||
cic_disabled = 0, /* Checksum Insertion Control */
|
||||
cic_only_ip = 1, /* Only IP header */
|
||||
/* IP header but pseudoheader is not calculated */
|
||||
cic_no_pseudoheader = 2,
|
||||
cic_full = 3, /* IP header and pseudoheader */
|
||||
};
|
||||
|
||||
/* Extended RDES4 definitions */
|
||||
#define RDES_EXT_NO_PTP 0
|
||||
#define RDES_EXT_SYNC 0x1
|
||||
#define RDES_EXT_FOLLOW_UP 0x2
|
||||
#define RDES_EXT_DELAY_REQ 0x3
|
||||
#define RDES_EXT_DELAY_RESP 0x4
|
||||
#define RDES_EXT_PDELAY_REQ 0x5
|
||||
#define RDES_EXT_PDELAY_RESP 0x6
|
||||
#define RDES_EXT_PDELAY_FOLLOW_UP 0x7
|
||||
|
||||
#endif /* __DESCS_H__ */
|
||||
134
drivers/net/ethernet/rockchip/gmac/descs_com.h
Executable file
134
drivers/net/ethernet/rockchip/gmac/descs_com.h
Executable file
@@ -0,0 +1,134 @@
|
||||
/*******************************************************************************
|
||||
Header File to describe Normal/enhanced descriptor functions used for RING
|
||||
and CHAINED modes.
|
||||
|
||||
Copyright(C) 2011 STMicroelectronics Ltd
|
||||
|
||||
It defines all the functions used to handle the normal/enhanced
|
||||
descriptors in case of the DMA is configured to work in chained or
|
||||
in ring mode.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DESC_COM_H__
|
||||
#define __DESC_COM_H__
|
||||
|
||||
/* Specific functions used for Ring mode */
|
||||
|
||||
/* Enhanced descriptors */
|
||||
static inline void ehn_desc_rx_set_on_ring(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
|
||||
if (end)
|
||||
p->des01.erx.end_ring = 1;
|
||||
}
|
||||
|
||||
static inline void ehn_desc_tx_set_on_ring(struct dma_desc *p, int end)
|
||||
{
|
||||
if (end)
|
||||
p->des01.etx.end_ring = 1;
|
||||
}
|
||||
|
||||
static inline void enh_desc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
|
||||
{
|
||||
p->des01.etx.end_ring = ter;
|
||||
}
|
||||
|
||||
static inline void enh_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
|
||||
{
|
||||
if (unlikely(len > BUF_SIZE_4KiB)) {
|
||||
p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
|
||||
p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
|
||||
} else
|
||||
p->des01.etx.buffer1_size = len;
|
||||
}
|
||||
|
||||
/* Normal descriptors */
|
||||
static inline void ndesc_rx_set_on_ring(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des01.rx.buffer2_size = BUF_SIZE_2KiB - 1;
|
||||
if (end)
|
||||
p->des01.rx.end_ring = 1;
|
||||
}
|
||||
|
||||
static inline void ndesc_tx_set_on_ring(struct dma_desc *p, int end)
|
||||
{
|
||||
if (end)
|
||||
p->des01.tx.end_ring = 1;
|
||||
}
|
||||
|
||||
static inline void ndesc_end_tx_desc_on_ring(struct dma_desc *p, int ter)
|
||||
{
|
||||
p->des01.tx.end_ring = ter;
|
||||
}
|
||||
|
||||
static inline void norm_set_tx_desc_len_on_ring(struct dma_desc *p, int len)
|
||||
{
|
||||
if (unlikely(len > BUF_SIZE_2KiB)) {
|
||||
p->des01.etx.buffer1_size = BUF_SIZE_2KiB - 1;
|
||||
p->des01.etx.buffer2_size = len - p->des01.etx.buffer1_size;
|
||||
} else
|
||||
p->des01.tx.buffer1_size = len;
|
||||
}
|
||||
|
||||
/* Specific functions used for Chain mode */
|
||||
|
||||
/* Enhanced descriptors */
|
||||
static inline void ehn_desc_rx_set_on_chain(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des01.erx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void ehn_desc_tx_set_on_chain(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des01.etx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void enh_desc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
|
||||
{
|
||||
p->des01.etx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void enh_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
|
||||
{
|
||||
p->des01.etx.buffer1_size = len;
|
||||
}
|
||||
|
||||
/* Normal descriptors */
|
||||
static inline void ndesc_rx_set_on_chain(struct dma_desc *p, int end)
|
||||
{
|
||||
p->des01.rx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void ndesc_tx_set_on_chain(struct dma_desc *p, int ring_size)
|
||||
{
|
||||
p->des01.tx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void ndesc_end_tx_desc_on_chain(struct dma_desc *p, int ter)
|
||||
{
|
||||
p->des01.tx.second_address_chained = 1;
|
||||
}
|
||||
|
||||
static inline void norm_set_tx_desc_len_on_chain(struct dma_desc *p, int len)
|
||||
{
|
||||
p->des01.tx.buffer1_size = len;
|
||||
}
|
||||
#endif /* __DESC_COM_H__ */
|
||||
126
drivers/net/ethernet/rockchip/gmac/dwmac100.h
Executable file
126
drivers/net/ethernet/rockchip/gmac/dwmac100.h
Executable file
@@ -0,0 +1,126 @@
|
||||
/*******************************************************************************
|
||||
MAC 10/100 Header File
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC100_H__
|
||||
#define __DWMAC100_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* MAC BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
/* MAC CSR offset */
|
||||
#define MAC_CONTROL 0x00000000 /* MAC Control */
|
||||
#define MAC_ADDR_HIGH 0x00000004 /* MAC Address High */
|
||||
#define MAC_ADDR_LOW 0x00000008 /* MAC Address Low */
|
||||
#define MAC_HASH_HIGH 0x0000000c /* Multicast Hash Table High */
|
||||
#define MAC_HASH_LOW 0x00000010 /* Multicast Hash Table Low */
|
||||
#define MAC_MII_ADDR 0x00000014 /* MII Address */
|
||||
#define MAC_MII_DATA 0x00000018 /* MII Data */
|
||||
#define MAC_FLOW_CTRL 0x0000001c /* Flow Control */
|
||||
#define MAC_VLAN1 0x00000020 /* VLAN1 Tag */
|
||||
#define MAC_VLAN2 0x00000024 /* VLAN2 Tag */
|
||||
|
||||
/* MAC CTRL defines */
|
||||
#define MAC_CONTROL_RA 0x80000000 /* Receive All Mode */
|
||||
#define MAC_CONTROL_BLE 0x40000000 /* Endian Mode */
|
||||
#define MAC_CONTROL_HBD 0x10000000 /* Heartbeat Disable */
|
||||
#define MAC_CONTROL_PS 0x08000000 /* Port Select */
|
||||
#define MAC_CONTROL_DRO 0x00800000 /* Disable Receive Own */
|
||||
#define MAC_CONTROL_EXT_LOOPBACK 0x00400000 /* Reserved (ext loopback?) */
|
||||
#define MAC_CONTROL_OM 0x00200000 /* Loopback Operating Mode */
|
||||
#define MAC_CONTROL_F 0x00100000 /* Full Duplex Mode */
|
||||
#define MAC_CONTROL_PM 0x00080000 /* Pass All Multicast */
|
||||
#define MAC_CONTROL_PR 0x00040000 /* Promiscuous Mode */
|
||||
#define MAC_CONTROL_IF 0x00020000 /* Inverse Filtering */
|
||||
#define MAC_CONTROL_PB 0x00010000 /* Pass Bad Frames */
|
||||
#define MAC_CONTROL_HO 0x00008000 /* Hash Only Filtering Mode */
|
||||
#define MAC_CONTROL_HP 0x00002000 /* Hash/Perfect Filtering Mode */
|
||||
#define MAC_CONTROL_LCC 0x00001000 /* Late Collision Control */
|
||||
#define MAC_CONTROL_DBF 0x00000800 /* Disable Broadcast Frames */
|
||||
#define MAC_CONTROL_DRTY 0x00000400 /* Disable Retry */
|
||||
#define MAC_CONTROL_ASTP 0x00000100 /* Automatic Pad Stripping */
|
||||
#define MAC_CONTROL_BOLMT_10 0x00000000 /* Back Off Limit 10 */
|
||||
#define MAC_CONTROL_BOLMT_8 0x00000040 /* Back Off Limit 8 */
|
||||
#define MAC_CONTROL_BOLMT_4 0x00000080 /* Back Off Limit 4 */
|
||||
#define MAC_CONTROL_BOLMT_1 0x000000c0 /* Back Off Limit 1 */
|
||||
#define MAC_CONTROL_DC 0x00000020 /* Deferral Check */
|
||||
#define MAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
|
||||
#define MAC_CONTROL_RE 0x00000004 /* Receiver Enable */
|
||||
|
||||
#define MAC_CORE_INIT (MAC_CONTROL_HBD | MAC_CONTROL_ASTP)
|
||||
|
||||
/* MAC FLOW CTRL defines */
|
||||
#define MAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
|
||||
#define MAC_FLOW_CTRL_PT_SHIFT 16
|
||||
#define MAC_FLOW_CTRL_PASS 0x00000004 /* Pass Control Frames */
|
||||
#define MAC_FLOW_CTRL_ENABLE 0x00000002 /* Flow Control Enable */
|
||||
#define MAC_FLOW_CTRL_PAUSE 0x00000001 /* Flow Control Busy ... */
|
||||
|
||||
/* MII ADDR defines */
|
||||
#define MAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
|
||||
#define MAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* DMA BLOCK defines
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_MODE_DBO 0x00100000 /* Descriptor Byte Ordering */
|
||||
#define DMA_BUS_MODE_BLE 0x00000080 /* Big Endian/Little Endian */
|
||||
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 8
|
||||
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
|
||||
#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
|
||||
#define DMA_BUS_MODE_BAR_BUS 0x00000002 /* Bar-Bus Arbitration */
|
||||
#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
|
||||
#define DMA_BUS_MODE_DEFAULT 0x00000000
|
||||
|
||||
/* DMA Control register defines */
|
||||
#define DMA_CONTROL_SF 0x00200000 /* Store And Forward */
|
||||
|
||||
/* Transmit Threshold Control */
|
||||
enum ttc_control {
|
||||
DMA_CONTROL_TTC_DEFAULT = 0x00000000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_64 = 0x00004000, /* Threshold is 64 DWORDS */
|
||||
DMA_CONTROL_TTC_128 = 0x00008000, /* Threshold is 128 DWORDS */
|
||||
DMA_CONTROL_TTC_256 = 0x0000c000, /* Threshold is 256 DWORDS */
|
||||
DMA_CONTROL_TTC_18 = 0x00400000, /* Threshold is 18 DWORDS */
|
||||
DMA_CONTROL_TTC_24 = 0x00404000, /* Threshold is 24 DWORDS */
|
||||
DMA_CONTROL_TTC_32 = 0x00408000, /* Threshold is 32 DWORDS */
|
||||
DMA_CONTROL_TTC_40 = 0x0040c000, /* Threshold is 40 DWORDS */
|
||||
DMA_CONTROL_SE = 0x00000008, /* Stop On Empty */
|
||||
DMA_CONTROL_OSF = 0x00000004, /* Operate On 2nd Frame */
|
||||
};
|
||||
|
||||
/* STMAC110 DMA Missed Frame Counter register defines */
|
||||
#define DMA_MISSED_FRAME_OVE 0x10000000 /* FIFO Overflow Overflow */
|
||||
#define DMA_MISSED_FRAME_OVE_CNTR 0x0ffe0000 /* Overflow Frame Counter */
|
||||
#define DMA_MISSED_FRAME_OVE_M 0x00010000 /* Missed Frame Overflow */
|
||||
#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
||||
|
||||
#endif /* __DWMAC100_H__ */
|
||||
269
drivers/net/ethernet/rockchip/gmac/dwmac1000.h
Executable file
269
drivers/net/ethernet/rockchip/gmac/dwmac1000.h
Executable file
@@ -0,0 +1,269 @@
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
#ifndef __DWMAC1000_H__
|
||||
#define __DWMAC1000_H__
|
||||
|
||||
#include <linux/phy.h>
|
||||
#include "common.h"
|
||||
|
||||
#define GMAC_CONTROL 0x00000000 /* Configuration */
|
||||
#define GMAC_FRAME_FILTER 0x00000004 /* Frame Filter */
|
||||
#define GMAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */
|
||||
#define GMAC_HASH_LOW 0x0000000c /* Multicast Hash Table Low */
|
||||
#define GMAC_MII_ADDR 0x00000010 /* MII Address */
|
||||
#define GMAC_MII_DATA 0x00000014 /* MII Data */
|
||||
#define GMAC_FLOW_CTRL 0x00000018 /* Flow Control */
|
||||
#define GMAC_VLAN_TAG 0x0000001c /* VLAN Tag */
|
||||
#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
|
||||
#define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */
|
||||
|
||||
#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */
|
||||
enum dwmac1000_irq_status {
|
||||
lpiis_irq = 0x400,
|
||||
time_stamp_irq = 0x0200,
|
||||
mmc_rx_csum_offload_irq = 0x0080,
|
||||
mmc_tx_irq = 0x0040,
|
||||
mmc_rx_irq = 0x0020,
|
||||
mmc_irq = 0x0010,
|
||||
pmt_irq = 0x0008,
|
||||
pcs_ane_irq = 0x0004,
|
||||
pcs_link_irq = 0x0002,
|
||||
rgmii_irq = 0x0001,
|
||||
};
|
||||
#define GMAC_INT_MASK 0x0000003c /* interrupt mask register */
|
||||
|
||||
/* PMT Control and Status */
|
||||
#define GMAC_PMT 0x0000002c
|
||||
enum power_event {
|
||||
pointer_reset = 0x80000000,
|
||||
global_unicast = 0x00000200,
|
||||
wake_up_rx_frame = 0x00000040,
|
||||
magic_frame = 0x00000020,
|
||||
wake_up_frame_en = 0x00000004,
|
||||
magic_pkt_en = 0x00000002,
|
||||
power_down = 0x00000001,
|
||||
};
|
||||
|
||||
/* Energy Efficient Ethernet (EEE)
|
||||
*
|
||||
* LPI status, timer and control register offset
|
||||
*/
|
||||
#define LPI_CTRL_STATUS 0x0030
|
||||
#define LPI_TIMER_CTRL 0x0034
|
||||
|
||||
/* LPI control and status defines */
|
||||
#define LPI_CTRL_STATUS_LPITXA 0x00080000 /* Enable LPI TX Automate */
|
||||
#define LPI_CTRL_STATUS_PLSEN 0x00040000 /* Enable PHY Link Status */
|
||||
#define LPI_CTRL_STATUS_PLS 0x00020000 /* PHY Link Status */
|
||||
#define LPI_CTRL_STATUS_LPIEN 0x00010000 /* LPI Enable */
|
||||
#define LPI_CTRL_STATUS_RLPIST 0x00000200 /* Receive LPI state */
|
||||
#define LPI_CTRL_STATUS_TLPIST 0x00000100 /* Transmit LPI state */
|
||||
#define LPI_CTRL_STATUS_RLPIEX 0x00000008 /* Receive LPI Exit */
|
||||
#define LPI_CTRL_STATUS_RLPIEN 0x00000004 /* Receive LPI Entry */
|
||||
#define LPI_CTRL_STATUS_TLPIEX 0x00000002 /* Transmit LPI Exit */
|
||||
#define LPI_CTRL_STATUS_TLPIEN 0x00000001 /* Transmit LPI Entry */
|
||||
|
||||
/* GMAC HW ADDR regs */
|
||||
#define GMAC_ADDR_HIGH(reg) (((reg > 15) ? 0x00000800 : 0x00000040) + \
|
||||
(reg * 8))
|
||||
#define GMAC_ADDR_LOW(reg) (((reg > 15) ? 0x00000804 : 0x00000044) + \
|
||||
(reg * 8))
|
||||
#define GMAC_MAX_PERFECT_ADDRESSES 32
|
||||
|
||||
/* PCS registers (AN/TBI/SGMII/RGMII) offset */
|
||||
#define GMAC_AN_CTRL 0x000000c0 /* AN control */
|
||||
#define GMAC_AN_STATUS 0x000000c4 /* AN status */
|
||||
#define GMAC_ANE_ADV 0x000000c8 /* Auto-Neg. Advertisement */
|
||||
#define GMAC_ANE_LPA 0x000000cc /* Auto-Neg. link partener ability */
|
||||
#define GMAC_ANE_EXP 0x000000d0 /* ANE expansion */
|
||||
#define GMAC_TBI 0x000000d4 /* TBI extend status */
|
||||
#define GMAC_S_R_GMII 0x000000d8 /* SGMII RGMII status */
|
||||
|
||||
/* AN Configuration defines */
|
||||
#define GMAC_AN_CTRL_RAN 0x00000200 /* Restart Auto-Negotiation */
|
||||
#define GMAC_AN_CTRL_ANE 0x00001000 /* Auto-Negotiation Enable */
|
||||
#define GMAC_AN_CTRL_ELE 0x00004000 /* External Loopback Enable */
|
||||
#define GMAC_AN_CTRL_ECD 0x00010000 /* Enable Comma Detect */
|
||||
#define GMAC_AN_CTRL_LR 0x00020000 /* Lock to Reference */
|
||||
#define GMAC_AN_CTRL_SGMRAL 0x00040000 /* SGMII RAL Control */
|
||||
|
||||
/* AN Status defines */
|
||||
#define GMAC_AN_STATUS_LS 0x00000004 /* Link Status 0:down 1:up */
|
||||
#define GMAC_AN_STATUS_ANA 0x00000008 /* Auto-Negotiation Ability */
|
||||
#define GMAC_AN_STATUS_ANC 0x00000020 /* Auto-Negotiation Complete */
|
||||
#define GMAC_AN_STATUS_ES 0x00000100 /* Extended Status */
|
||||
|
||||
/* Register 54 (SGMII/RGMII status register) */
|
||||
#define GMAC_S_R_GMII_LINK 0x8
|
||||
#define GMAC_S_R_GMII_SPEED 0x5
|
||||
#define GMAC_S_R_GMII_SPEED_SHIFT 0x1
|
||||
#define GMAC_S_R_GMII_MODE 0x1
|
||||
#define GMAC_S_R_GMII_SPEED_125 2
|
||||
#define GMAC_S_R_GMII_SPEED_25 1
|
||||
|
||||
/* Common ADV and LPA defines */
|
||||
#define GMAC_ANE_FD (1 << 5)
|
||||
#define GMAC_ANE_HD (1 << 6)
|
||||
#define GMAC_ANE_PSE (3 << 7)
|
||||
#define GMAC_ANE_PSE_SHIFT 7
|
||||
|
||||
/* GMAC Configuration defines */
|
||||
#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
|
||||
#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
|
||||
|
||||
/* GMAC Configuration defines */
|
||||
#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
|
||||
#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
|
||||
#define GMAC_CONTROL_JD 0x00400000 /* Jabber disable */
|
||||
#define GMAC_CONTROL_BE 0x00200000 /* Frame Burst Enable */
|
||||
#define GMAC_CONTROL_JE 0x00100000 /* Jumbo frame */
|
||||
enum inter_frame_gap {
|
||||
GMAC_CONTROL_IFG_88 = 0x00040000,
|
||||
GMAC_CONTROL_IFG_80 = 0x00020000,
|
||||
GMAC_CONTROL_IFG_40 = 0x000e0000,
|
||||
};
|
||||
#define GMAC_CONTROL_DCRS 0x00010000 /* Disable carrier sense */
|
||||
#define GMAC_CONTROL_PS 0x00008000 /* Port Select 0:GMI 1:MII */
|
||||
#define GMAC_CONTROL_FES 0x00004000 /* Speed 0:10 1:100 */
|
||||
#define GMAC_CONTROL_DO 0x00002000 /* Disable Rx Own */
|
||||
#define GMAC_CONTROL_LM 0x00001000 /* Loop-back mode */
|
||||
#define GMAC_CONTROL_DM 0x00000800 /* Duplex Mode */
|
||||
#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
|
||||
#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */
|
||||
#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */
|
||||
#define GMAC_CONTROL_ACS 0x00000080 /* Auto Pad/FCS Stripping */
|
||||
#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */
|
||||
#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
|
||||
#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
|
||||
|
||||
#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \
|
||||
GMAC_CONTROL_JE | GMAC_CONTROL_BE)
|
||||
|
||||
/* GMAC Frame Filter defines */
|
||||
#define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */
|
||||
#define GMAC_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */
|
||||
#define GMAC_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */
|
||||
#define GMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */
|
||||
#define GMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */
|
||||
#define GMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */
|
||||
#define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
|
||||
#define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
|
||||
#define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
|
||||
#define GMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
|
||||
/* GMII ADDR defines */
|
||||
#define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
|
||||
#define GMAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
|
||||
/* GMAC FLOW CTRL defines */
|
||||
#define GMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
|
||||
#define GMAC_FLOW_CTRL_PT_SHIFT 16
|
||||
#define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */
|
||||
#define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */
|
||||
#define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
|
||||
|
||||
/*--- DMA BLOCK defines ---*/
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
|
||||
#define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */
|
||||
#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
|
||||
#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
|
||||
/* Programmable burst length (passed thorugh platform)*/
|
||||
#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_PBL_SHIFT 8
|
||||
#define DMA_BUS_MODE_ATDS 0x00000080 /* Alternate Descriptor Size */
|
||||
|
||||
enum rx_tx_priority_ratio {
|
||||
double_ratio = 0x00004000, /* 2:1 */
|
||||
triple_ratio = 0x00008000, /* 3:1 */
|
||||
quadruple_ratio = 0x0000c000, /* 4:1 */
|
||||
};
|
||||
|
||||
#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */
|
||||
#define DMA_BUS_MODE_MB 0x04000000 /* Mixed burst */
|
||||
#define DMA_BUS_MODE_RPBL_MASK 0x003e0000 /* Rx-Programmable Burst Len */
|
||||
#define DMA_BUS_MODE_RPBL_SHIFT 17
|
||||
#define DMA_BUS_MODE_USP 0x00800000
|
||||
#define DMA_BUS_MODE_PBL 0x01000000
|
||||
#define DMA_BUS_MODE_AAL 0x02000000
|
||||
|
||||
/* DMA CRS Control and Status Register Mapping */
|
||||
#define DMA_HOST_TX_DESC 0x00001048 /* Current Host Tx descriptor */
|
||||
#define DMA_HOST_RX_DESC 0x0000104c /* Current Host Rx descriptor */
|
||||
/* DMA Bus Mode register defines */
|
||||
#define DMA_BUS_PR_RATIO_MASK 0x0000c000 /* Rx/Tx priority ratio */
|
||||
#define DMA_BUS_PR_RATIO_SHIFT 14
|
||||
#define DMA_BUS_FB 0x00010000 /* Fixed Burst */
|
||||
|
||||
/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/
|
||||
/* Disable Drop TCP/IP csum error */
|
||||
#define DMA_CONTROL_DT 0x04000000
|
||||
#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */
|
||||
#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */
|
||||
/* Threshold for Activating the FC */
|
||||
enum rfa {
|
||||
act_full_minus_1 = 0x00800000,
|
||||
act_full_minus_2 = 0x00800200,
|
||||
act_full_minus_3 = 0x00800400,
|
||||
act_full_minus_4 = 0x00800600,
|
||||
};
|
||||
/* Threshold for Deactivating the FC */
|
||||
enum rfd {
|
||||
deac_full_minus_1 = 0x00400000,
|
||||
deac_full_minus_2 = 0x00400800,
|
||||
deac_full_minus_3 = 0x00401000,
|
||||
deac_full_minus_4 = 0x00401800,
|
||||
};
|
||||
#define DMA_CONTROL_TSF 0x00200000 /* Transmit Store and Forward */
|
||||
|
||||
enum ttc_control {
|
||||
DMA_CONTROL_TTC_64 = 0x00000000,
|
||||
DMA_CONTROL_TTC_128 = 0x00004000,
|
||||
DMA_CONTROL_TTC_192 = 0x00008000,
|
||||
DMA_CONTROL_TTC_256 = 0x0000c000,
|
||||
DMA_CONTROL_TTC_40 = 0x00010000,
|
||||
DMA_CONTROL_TTC_32 = 0x00014000,
|
||||
DMA_CONTROL_TTC_24 = 0x00018000,
|
||||
DMA_CONTROL_TTC_16 = 0x0001c000,
|
||||
};
|
||||
#define DMA_CONTROL_TC_TX_MASK 0xfffe3fff
|
||||
|
||||
#define DMA_CONTROL_EFC 0x00000100
|
||||
#define DMA_CONTROL_FEF 0x00000080
|
||||
#define DMA_CONTROL_FUF 0x00000040
|
||||
|
||||
enum rtc_control {
|
||||
DMA_CONTROL_RTC_64 = 0x00000000,
|
||||
DMA_CONTROL_RTC_32 = 0x00000008,
|
||||
DMA_CONTROL_RTC_96 = 0x00000010,
|
||||
DMA_CONTROL_RTC_128 = 0x00000018,
|
||||
};
|
||||
#define DMA_CONTROL_TC_RX_MASK 0xffffffe7
|
||||
|
||||
#define DMA_CONTROL_OSF 0x00000004 /* Operate on second frame */
|
||||
|
||||
/* MMC registers offset */
|
||||
#define GMAC_MMC_CTRL 0x100
|
||||
#define GMAC_MMC_RX_INTR 0x104
|
||||
#define GMAC_MMC_TX_INTR 0x108
|
||||
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
|
||||
|
||||
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
|
||||
#endif /* __DWMAC1000_H__ */
|
||||
408
drivers/net/ethernet/rockchip/gmac/dwmac1000_core.c
Executable file
408
drivers/net/ethernet/rockchip/gmac/dwmac1000_core.c
Executable file
@@ -0,0 +1,408 @@
|
||||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <asm/io.h>
|
||||
#include "dwmac1000.h"
|
||||
|
||||
static void dwmac1000_core_init(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
value |= GMAC_CORE_INIT;
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
|
||||
/* Mask GMAC interrupts */
|
||||
writel(0x207, ioaddr + GMAC_INT_MASK);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
/* Tag detection without filtering */
|
||||
writel(0x0, ioaddr + GMAC_VLAN_TAG);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
value |= GMAC_CONTROL_IPC;
|
||||
writel(value, ioaddr + GMAC_CONTROL);
|
||||
|
||||
value = readl(ioaddr + GMAC_CONTROL);
|
||||
|
||||
return !!(value & GMAC_CONTROL_IPC);
|
||||
}
|
||||
|
||||
static void dwmac1000_dump_regs(void __iomem *ioaddr)
|
||||
{
|
||||
int i;
|
||||
pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr);
|
||||
|
||||
for (i = 0; i < 55; i++) {
|
||||
int offset = i * 4;
|
||||
pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
|
||||
offset, readl(ioaddr + offset));
|
||||
}
|
||||
}
|
||||
|
||||
static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
|
||||
GMAC_ADDR_LOW(reg_n));
|
||||
}
|
||||
|
||||
static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
|
||||
GMAC_ADDR_LOW(reg_n));
|
||||
}
|
||||
|
||||
static void dwmac1000_set_filter(struct net_device *dev, int id)
|
||||
{
|
||||
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
|
||||
unsigned int value = 0;
|
||||
unsigned int perfect_addr_number;
|
||||
|
||||
CHIP_DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
|
||||
__func__, netdev_mc_count(dev), netdev_uc_count(dev));
|
||||
|
||||
if (dev->flags & IFF_PROMISC)
|
||||
value = GMAC_FRAME_FILTER_PR;
|
||||
else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
|
||||
|| (dev->flags & IFF_ALLMULTI)) {
|
||||
value = GMAC_FRAME_FILTER_PM; /* pass all multi */
|
||||
writel(0xffffffff, ioaddr + GMAC_HASH_HIGH);
|
||||
writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
|
||||
} else if (!netdev_mc_empty(dev)) {
|
||||
u32 mc_filter[2];
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
/* Hash filter for multicast */
|
||||
value = GMAC_FRAME_FILTER_HMC;
|
||||
|
||||
memset(mc_filter, 0, sizeof(mc_filter));
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
/* The upper 6 bits of the calculated CRC are used to
|
||||
* index the contens of the hash table
|
||||
*/
|
||||
int bit_nr = bitrev32(~crc32_le(~0, ha->addr, 6)) >> 26;
|
||||
/* The most significant bit determines the register to
|
||||
* use (H/L) while the other 5 bits determine the bit
|
||||
* within the register.
|
||||
*/
|
||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||
}
|
||||
writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
|
||||
writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
|
||||
}
|
||||
|
||||
/* Extra 16 regs are available in cores newer than the 3.40. */
|
||||
if (id > DWMAC_CORE_3_40)
|
||||
perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES;
|
||||
else
|
||||
perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES / 2;
|
||||
|
||||
/* Handle multiple unicast addresses (perfect filtering) */
|
||||
if (netdev_uc_count(dev) > perfect_addr_number)
|
||||
/* Switch to promiscuous mode if more than 16 addrs
|
||||
* are required
|
||||
*/
|
||||
value |= GMAC_FRAME_FILTER_PR;
|
||||
else {
|
||||
int reg = 1;
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
netdev_for_each_uc_addr(ha, dev) {
|
||||
dwmac1000_set_umac_addr(ioaddr, ha->addr, reg);
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FRAME_FILTER_DEBUG
|
||||
/* Enable Receive all mode (to debug filtering_fail errors) */
|
||||
value |= GMAC_FRAME_FILTER_RA;
|
||||
#endif
|
||||
writel(value, ioaddr + GMAC_FRAME_FILTER);
|
||||
|
||||
CHIP_DBG(KERN_INFO "\tFilter: 0x%08x\n\tHash: HI 0x%08x, LO 0x%08x\n",
|
||||
readl(ioaddr + GMAC_FRAME_FILTER),
|
||||
readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
|
||||
}
|
||||
|
||||
static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time)
|
||||
{
|
||||
unsigned int flow = 0;
|
||||
|
||||
CHIP_DBG(KERN_DEBUG "GMAC Flow-Control:\n");
|
||||
if (fc & FLOW_RX) {
|
||||
CHIP_DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
|
||||
flow |= GMAC_FLOW_CTRL_RFE;
|
||||
}
|
||||
if (fc & FLOW_TX) {
|
||||
CHIP_DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n");
|
||||
flow |= GMAC_FLOW_CTRL_TFE;
|
||||
}
|
||||
|
||||
if (duplex) {
|
||||
CHIP_DBG(KERN_DEBUG "\tduplex mode: PAUSE %d\n", pause_time);
|
||||
flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
|
||||
}
|
||||
|
||||
writel(flow, ioaddr + GMAC_FLOW_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
|
||||
{
|
||||
unsigned int pmt = 0;
|
||||
|
||||
if (mode & WAKE_MAGIC) {
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
|
||||
pmt |= power_down | magic_pkt_en;
|
||||
}
|
||||
if (mode & WAKE_UCAST) {
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
|
||||
pmt |= global_unicast;
|
||||
}
|
||||
|
||||
writel(pmt, ioaddr + GMAC_PMT);
|
||||
}
|
||||
|
||||
static int dwmac1000_irq_status(void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
|
||||
int ret = 0;
|
||||
|
||||
/* Not used events (e.g. MMC interrupts) are not handled. */
|
||||
if ((intr_status & mmc_tx_irq)) {
|
||||
CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n",
|
||||
readl(ioaddr + GMAC_MMC_TX_INTR));
|
||||
x->mmc_tx_irq_n++;
|
||||
}
|
||||
if (unlikely(intr_status & mmc_rx_irq)) {
|
||||
CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n",
|
||||
readl(ioaddr + GMAC_MMC_RX_INTR));
|
||||
x->mmc_rx_irq_n++;
|
||||
}
|
||||
if (unlikely(intr_status & mmc_rx_csum_offload_irq)) {
|
||||
CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n",
|
||||
readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
|
||||
x->mmc_rx_csum_offload_irq_n++;
|
||||
}
|
||||
if (unlikely(intr_status & pmt_irq)) {
|
||||
CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n");
|
||||
/* clear the PMT bits 5 and 6 by reading the PMT status reg */
|
||||
readl(ioaddr + GMAC_PMT);
|
||||
x->irq_receive_pmt_irq_n++;
|
||||
}
|
||||
/* MAC trx/rx EEE LPI entry/exit interrupts */
|
||||
if (intr_status & lpiis_irq) {
|
||||
/* Clean LPI interrupt by reading the Reg 12 */
|
||||
ret = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
|
||||
if (ret & LPI_CTRL_STATUS_TLPIEN) {
|
||||
CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n");
|
||||
x->irq_tx_path_in_lpi_mode_n++;
|
||||
}
|
||||
if (ret & LPI_CTRL_STATUS_TLPIEX) {
|
||||
CHIP_DBG(KERN_INFO "GMAC TX exit from LPI\n");
|
||||
x->irq_tx_path_exit_lpi_mode_n++;
|
||||
}
|
||||
if (ret & LPI_CTRL_STATUS_RLPIEN) {
|
||||
CHIP_DBG(KERN_INFO "GMAC RX entered in LPI\n");
|
||||
x->irq_rx_path_in_lpi_mode_n++;
|
||||
}
|
||||
if (ret & LPI_CTRL_STATUS_RLPIEX) {
|
||||
CHIP_DBG(KERN_INFO "GMAC RX exit from LPI\n");
|
||||
x->irq_rx_path_exit_lpi_mode_n++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((intr_status & pcs_ane_irq) || (intr_status & pcs_link_irq)) {
|
||||
CHIP_DBG(KERN_INFO "GMAC PCS ANE IRQ\n");
|
||||
readl(ioaddr + GMAC_AN_STATUS);
|
||||
x->irq_pcs_ane_n++;
|
||||
}
|
||||
if (intr_status & rgmii_irq) {
|
||||
u32 status = readl(ioaddr + GMAC_S_R_GMII);
|
||||
CHIP_DBG(KERN_INFO "GMAC RGMII/SGMII interrupt\n");
|
||||
x->irq_rgmii_n++;
|
||||
|
||||
/* Save and dump the link status. */
|
||||
if (status & GMAC_S_R_GMII_LINK) {
|
||||
int speed_value = (status & GMAC_S_R_GMII_SPEED) >>
|
||||
GMAC_S_R_GMII_SPEED_SHIFT;
|
||||
x->pcs_duplex = (status & GMAC_S_R_GMII_MODE);
|
||||
|
||||
if (speed_value == GMAC_S_R_GMII_SPEED_125)
|
||||
x->pcs_speed = SPEED_1000;
|
||||
else if (speed_value == GMAC_S_R_GMII_SPEED_25)
|
||||
x->pcs_speed = SPEED_100;
|
||||
else
|
||||
x->pcs_speed = SPEED_10;
|
||||
|
||||
x->pcs_link = 1;
|
||||
pr_debug("Link is Up - %d/%s\n", (int)x->pcs_speed,
|
||||
x->pcs_duplex ? "Full" : "Half");
|
||||
} else {
|
||||
x->pcs_link = 0;
|
||||
pr_debug("Link is Down\n");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
/* Enable the link status receive on RGMII, SGMII ore SMII
|
||||
* receive path and instruct the transmit to enter in LPI
|
||||
* state.
|
||||
*/
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_reset_eee_mode(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + LPI_CTRL_STATUS);
|
||||
|
||||
if (link)
|
||||
value |= LPI_CTRL_STATUS_PLS;
|
||||
else
|
||||
value &= ~LPI_CTRL_STATUS_PLS;
|
||||
|
||||
writel(value, ioaddr + LPI_CTRL_STATUS);
|
||||
}
|
||||
|
||||
static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
|
||||
{
|
||||
int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
|
||||
|
||||
/* Program the timers in the LPI timer control register:
|
||||
* LS: minimum time (ms) for which the link
|
||||
* status from PHY should be ok before transmitting
|
||||
* the LPI pattern.
|
||||
* TW: minimum time (us) for which the core waits
|
||||
* after it has stopped transmitting the LPI pattern.
|
||||
*/
|
||||
writel(value, ioaddr + LPI_TIMER_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(ioaddr + GMAC_AN_CTRL);
|
||||
/* auto negotiation enable and External Loopback enable */
|
||||
value = GMAC_AN_CTRL_ANE | GMAC_AN_CTRL_ELE;
|
||||
|
||||
if (restart)
|
||||
value |= GMAC_AN_CTRL_RAN;
|
||||
|
||||
writel(value, ioaddr + GMAC_AN_CTRL);
|
||||
}
|
||||
|
||||
static void dwmac1000_get_adv(void __iomem *ioaddr, struct rgmii_adv *adv)
|
||||
{
|
||||
u32 value = readl(ioaddr + GMAC_ANE_ADV);
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv->duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv->duplex |= DUPLEX_HALF;
|
||||
|
||||
adv->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
|
||||
value = readl(ioaddr + GMAC_ANE_LPA);
|
||||
|
||||
if (value & GMAC_ANE_FD)
|
||||
adv->lp_duplex = DUPLEX_FULL;
|
||||
if (value & GMAC_ANE_HD)
|
||||
adv->lp_duplex = DUPLEX_HALF;
|
||||
|
||||
adv->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
|
||||
}
|
||||
|
||||
static const struct stmmac_ops dwmac1000_ops = {
|
||||
.core_init = dwmac1000_core_init,
|
||||
.rx_ipc = dwmac1000_rx_ipc_enable,
|
||||
.dump_regs = dwmac1000_dump_regs,
|
||||
.host_irq_status = dwmac1000_irq_status,
|
||||
.set_filter = dwmac1000_set_filter,
|
||||
.flow_ctrl = dwmac1000_flow_ctrl,
|
||||
.pmt = dwmac1000_pmt,
|
||||
.set_umac_addr = dwmac1000_set_umac_addr,
|
||||
.get_umac_addr = dwmac1000_get_umac_addr,
|
||||
.set_eee_mode = dwmac1000_set_eee_mode,
|
||||
.reset_eee_mode = dwmac1000_reset_eee_mode,
|
||||
.set_eee_timer = dwmac1000_set_eee_timer,
|
||||
.set_eee_pls = dwmac1000_set_eee_pls,
|
||||
.ctrl_ane = dwmac1000_ctrl_ane,
|
||||
.get_adv = dwmac1000_get_adv,
|
||||
};
|
||||
|
||||
struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
|
||||
{
|
||||
struct mac_device_info *mac;
|
||||
u32 hwid = readl(ioaddr + GMAC_VERSION);
|
||||
|
||||
mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
|
||||
if (!mac)
|
||||
return NULL;
|
||||
|
||||
mac->mac = &dwmac1000_ops;
|
||||
mac->dma = &dwmac1000_dma_ops;
|
||||
|
||||
mac->link.port = GMAC_CONTROL_PS;
|
||||
mac->link.duplex = GMAC_CONTROL_DM;
|
||||
mac->link.speed = GMAC_CONTROL_FES;
|
||||
mac->mii.addr = GMAC_MII_ADDR;
|
||||
mac->mii.data = GMAC_MII_DATA;
|
||||
mac->synopsys_uid = hwid;
|
||||
|
||||
return mac;
|
||||
}
|
||||
203
drivers/net/ethernet/rockchip/gmac/dwmac1000_dma.c
Executable file
203
drivers/net/ethernet/rockchip/gmac/dwmac1000_dma.c
Executable file
@@ -0,0 +1,203 @@
|
||||
/*******************************************************************************
|
||||
This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
|
||||
DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
|
||||
developing this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include "dwmac1000.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
|
||||
int burst_len, u32 dma_tx, u32 dma_rx, int atds)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_BUS_MODE);
|
||||
int limit;
|
||||
|
||||
/* DMA SW reset */
|
||||
value |= DMA_BUS_MODE_SFT_RESET;
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* Set the DMA PBL (Programmable Burst Length) mode
|
||||
* Before stmmac core 3.50 this mode bit was 4xPBL, and
|
||||
* post 3.5 mode bit acts as 8*PBL.
|
||||
* For core rev < 3.5, when the core is set for 4xPBL mode, the
|
||||
* DMA transfers the data in 4, 8, 16, 32, 64 & 128 beats
|
||||
* depending on pbl value.
|
||||
* For core rev > 3.5, when the core is set for 8xPBL mode, the
|
||||
* DMA transfers the data in 8, 16, 32, 64, 128 & 256 beats
|
||||
* depending on pbl value.
|
||||
*/
|
||||
value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
|
||||
(pbl << DMA_BUS_MODE_RPBL_SHIFT));
|
||||
|
||||
/* Set the Fixed burst mode */
|
||||
if (fb)
|
||||
value |= DMA_BUS_MODE_FB;
|
||||
|
||||
/* Mixed Burst has no effect when fb is set */
|
||||
if (mb)
|
||||
value |= DMA_BUS_MODE_MB;
|
||||
|
||||
#ifdef CONFIG_GMAC_DA
|
||||
value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
|
||||
#endif
|
||||
|
||||
if (atds)
|
||||
value |= DMA_BUS_MODE_ATDS;
|
||||
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE
|
||||
* for supported bursts.
|
||||
*
|
||||
* Note: This is applicable only for revision GMACv3.61a. For
|
||||
* older version this register is reserved and shall have no
|
||||
* effect.
|
||||
*
|
||||
* Note:
|
||||
* For Fixed Burst Mode: if we directly write 0xFF to this
|
||||
* register using the configurations pass from platform code,
|
||||
* this would ensure that all bursts supported by core are set
|
||||
* and those which are not supported would remain ineffective.
|
||||
*
|
||||
* For Non Fixed Burst Mode: provide the maximum value of the
|
||||
* burst length. Any burst equal or below the provided burst
|
||||
* length would be allowed to perform.
|
||||
*/
|
||||
writel(burst_len, ioaddr + DMA_AXI_BUS_MODE);
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
|
||||
|
||||
/* RX/TX descriptor base address lists must be written into
|
||||
* DMA CSR3 and CSR4, respectively
|
||||
*/
|
||||
writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
|
||||
writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
|
||||
int rxmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
|
||||
if (txmode == SF_DMA_MODE) {
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: enable TX store and forward mode\n");
|
||||
/* Transmit COE type 2 cannot be done in cut-through mode. */
|
||||
csr6 |= DMA_CONTROL_TSF;
|
||||
/* Operating on second frame increase the performance
|
||||
* especially when transmit store-and-forward is used.
|
||||
*/
|
||||
csr6 |= DMA_CONTROL_OSF;
|
||||
} else {
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: disabling TX SF (threshold %d)\n",
|
||||
txmode);
|
||||
csr6 &= ~DMA_CONTROL_TSF;
|
||||
csr6 &= DMA_CONTROL_TC_TX_MASK;
|
||||
/* Set the transmit threshold */
|
||||
if (txmode <= 32)
|
||||
csr6 |= DMA_CONTROL_TTC_32;
|
||||
else if (txmode <= 64)
|
||||
csr6 |= DMA_CONTROL_TTC_64;
|
||||
else if (txmode <= 128)
|
||||
csr6 |= DMA_CONTROL_TTC_128;
|
||||
else if (txmode <= 192)
|
||||
csr6 |= DMA_CONTROL_TTC_192;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_TTC_256;
|
||||
}
|
||||
|
||||
if (rxmode == SF_DMA_MODE) {
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: enable RX store and forward mode\n");
|
||||
csr6 |= DMA_CONTROL_RSF;
|
||||
} else {
|
||||
CHIP_DBG(KERN_DEBUG "GMAC: disable RX SF mode (threshold %d)\n",
|
||||
rxmode);
|
||||
csr6 &= ~DMA_CONTROL_RSF;
|
||||
csr6 &= DMA_CONTROL_TC_RX_MASK;
|
||||
if (rxmode <= 32)
|
||||
csr6 |= DMA_CONTROL_RTC_32;
|
||||
else if (rxmode <= 64)
|
||||
csr6 |= DMA_CONTROL_RTC_64;
|
||||
else if (rxmode <= 96)
|
||||
csr6 |= DMA_CONTROL_RTC_96;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_RTC_128;
|
||||
}
|
||||
|
||||
writel(csr6, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
static void dwmac1000_dump_dma_regs(void __iomem *ioaddr)
|
||||
{
|
||||
int i;
|
||||
pr_info(" DMA registers\n");
|
||||
for (i = 0; i < 22; i++) {
|
||||
if ((i < 9) || (i > 17)) {
|
||||
int offset = i * 4;
|
||||
pr_err("\t Reg No. %d (offset 0x%x): 0x%08x\n", i,
|
||||
(DMA_BUS_MODE + offset),
|
||||
readl(ioaddr + DMA_BUS_MODE + offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int dwmac1000_get_hw_feature(void __iomem *ioaddr)
|
||||
{
|
||||
return readl(ioaddr + DMA_HW_FEATURE);
|
||||
}
|
||||
|
||||
static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt)
|
||||
{
|
||||
writel(riwt, ioaddr + DMA_RX_WATCHDOG);
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac1000_dma_ops = {
|
||||
.init = dwmac1000_dma_init,
|
||||
.dump_regs = dwmac1000_dump_dma_regs,
|
||||
.dma_mode = dwmac1000_dma_operation_mode,
|
||||
.enable_dma_transmission = dwmac_enable_dma_transmission,
|
||||
.enable_dma_irq = dwmac_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac_disable_dma_irq,
|
||||
.start_tx = dwmac_dma_start_tx,
|
||||
.stop_tx = dwmac_dma_stop_tx,
|
||||
.start_rx = dwmac_dma_start_rx,
|
||||
.stop_rx = dwmac_dma_stop_rx,
|
||||
.dma_interrupt = dwmac_dma_interrupt,
|
||||
.get_hw_feature = dwmac1000_get_hw_feature,
|
||||
.rx_watchdog = dwmac1000_rx_watchdog,
|
||||
};
|
||||
193
drivers/net/ethernet/rockchip/gmac/dwmac100_core.c
Executable file
193
drivers/net/ethernet/rockchip/gmac/dwmac100_core.c
Executable file
@@ -0,0 +1,193 @@
|
||||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This only implements the mac core functions for this chip.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
#include <asm/io.h>
|
||||
#include "dwmac100.h"
|
||||
|
||||
static void dwmac100_core_init(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
|
||||
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
|
||||
{
|
||||
pr_info("\t----------------------------------------------\n"
|
||||
"\t DWMAC 100 CSR (base addr = 0x%p)\n"
|
||||
"\t----------------------------------------------\n", ioaddr);
|
||||
pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
|
||||
readl(ioaddr + MAC_CONTROL));
|
||||
pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
|
||||
readl(ioaddr + MAC_ADDR_HIGH));
|
||||
pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
|
||||
readl(ioaddr + MAC_ADDR_LOW));
|
||||
pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
|
||||
MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
|
||||
pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
|
||||
MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
|
||||
pr_info("\tflow control (offset 0x%x): 0x%08x\n",
|
||||
MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL));
|
||||
pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1,
|
||||
readl(ioaddr + MAC_VLAN1));
|
||||
pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
|
||||
readl(ioaddr + MAC_VLAN2));
|
||||
}
|
||||
|
||||
static int dwmac100_rx_ipc_enable(void __iomem *ioaddr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dwmac100_irq_status(void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
|
||||
}
|
||||
|
||||
static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int reg_n)
|
||||
{
|
||||
stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
|
||||
}
|
||||
|
||||
static void dwmac100_set_filter(struct net_device *dev, int id)
|
||||
{
|
||||
void __iomem *ioaddr = (void __iomem *)dev->base_addr;
|
||||
u32 value = readl(ioaddr + MAC_CONTROL);
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
value |= MAC_CONTROL_PR;
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
|
||||
MAC_CONTROL_HP);
|
||||
} else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
|
||||
|| (dev->flags & IFF_ALLMULTI)) {
|
||||
value |= MAC_CONTROL_PM;
|
||||
value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
|
||||
writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
|
||||
writel(0xffffffff, ioaddr + MAC_HASH_LOW);
|
||||
} else if (netdev_mc_empty(dev)) { /* no multicast */
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
|
||||
MAC_CONTROL_HO | MAC_CONTROL_HP);
|
||||
} else {
|
||||
u32 mc_filter[2];
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
/* Perfect filter mode for physical address and Hash
|
||||
* filter for multicast
|
||||
*/
|
||||
value |= MAC_CONTROL_HP;
|
||||
value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |
|
||||
MAC_CONTROL_IF | MAC_CONTROL_HO);
|
||||
|
||||
memset(mc_filter, 0, sizeof(mc_filter));
|
||||
netdev_for_each_mc_addr(ha, dev) {
|
||||
/* The upper 6 bits of the calculated CRC are used to
|
||||
* index the contens of the hash table
|
||||
*/
|
||||
int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
|
||||
/* The most significant bit determines the register to
|
||||
* use (H/L) while the other 5 bits determine the bit
|
||||
* within the register.
|
||||
*/
|
||||
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
|
||||
}
|
||||
writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
|
||||
writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
|
||||
}
|
||||
|
||||
writel(value, ioaddr + MAC_CONTROL);
|
||||
|
||||
CHIP_DBG(KERN_INFO "%s: Filter: 0x%08x Hash: HI 0x%08x, LO 0x%08x\n",
|
||||
__func__, readl(ioaddr + MAC_CONTROL),
|
||||
readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
|
||||
}
|
||||
|
||||
static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
|
||||
unsigned int fc, unsigned int pause_time)
|
||||
{
|
||||
unsigned int flow = MAC_FLOW_CTRL_ENABLE;
|
||||
|
||||
if (duplex)
|
||||
flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
|
||||
writel(flow, ioaddr + MAC_FLOW_CTRL);
|
||||
}
|
||||
|
||||
/* No PMT module supported on ST boards with this Eth chip. */
|
||||
static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct stmmac_ops dwmac100_ops = {
|
||||
.core_init = dwmac100_core_init,
|
||||
.rx_ipc = dwmac100_rx_ipc_enable,
|
||||
.dump_regs = dwmac100_dump_mac_regs,
|
||||
.host_irq_status = dwmac100_irq_status,
|
||||
.set_filter = dwmac100_set_filter,
|
||||
.flow_ctrl = dwmac100_flow_ctrl,
|
||||
.pmt = dwmac100_pmt,
|
||||
.set_umac_addr = dwmac100_set_umac_addr,
|
||||
.get_umac_addr = dwmac100_get_umac_addr,
|
||||
};
|
||||
|
||||
struct mac_device_info *dwmac100_setup(void __iomem *ioaddr)
|
||||
{
|
||||
struct mac_device_info *mac;
|
||||
|
||||
mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
|
||||
if (!mac)
|
||||
return NULL;
|
||||
|
||||
pr_info("\tDWMAC100\n");
|
||||
|
||||
mac->mac = &dwmac100_ops;
|
||||
mac->dma = &dwmac100_dma_ops;
|
||||
|
||||
mac->link.port = MAC_CONTROL_PS;
|
||||
mac->link.duplex = MAC_CONTROL_F;
|
||||
mac->link.speed = 0;
|
||||
mac->mii.addr = MAC_MII_ADDR;
|
||||
mac->mii.data = MAC_MII_DATA;
|
||||
mac->synopsys_uid = 0;
|
||||
|
||||
return mac;
|
||||
}
|
||||
146
drivers/net/ethernet/rockchip/gmac/dwmac100_dma.c
Executable file
146
drivers/net/ethernet/rockchip/gmac/dwmac100_dma.c
Executable file
@@ -0,0 +1,146 @@
|
||||
/*******************************************************************************
|
||||
This is the driver for the MAC 10/100 on-chip Ethernet controller
|
||||
currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
|
||||
|
||||
DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
|
||||
this code.
|
||||
|
||||
This contains the functions to handle the dma.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include "dwmac100.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
|
||||
int burst_len, u32 dma_tx, u32 dma_rx, int atds)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_BUS_MODE);
|
||||
int limit;
|
||||
|
||||
/* DMA SW reset */
|
||||
value |= DMA_BUS_MODE_SFT_RESET;
|
||||
writel(value, ioaddr + DMA_BUS_MODE);
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
/* Enable Application Access by writing to DMA CSR0 */
|
||||
writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
|
||||
ioaddr + DMA_BUS_MODE);
|
||||
|
||||
/* Mask interrupts by writing to CSR7 */
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
|
||||
|
||||
/* RX/TX descriptor base addr lists must be written into
|
||||
* DMA CSR3 and CSR4, respectively
|
||||
*/
|
||||
writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
|
||||
writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Store and Forward capability is not used at all.
|
||||
*
|
||||
* The transmit threshold can be programmed by setting the TTC bits in the DMA
|
||||
* control register.
|
||||
*/
|
||||
static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode,
|
||||
int rxmode)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
|
||||
if (txmode <= 32)
|
||||
csr6 |= DMA_CONTROL_TTC_32;
|
||||
else if (txmode <= 64)
|
||||
csr6 |= DMA_CONTROL_TTC_64;
|
||||
else
|
||||
csr6 |= DMA_CONTROL_TTC_128;
|
||||
|
||||
writel(csr6, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
static void dwmac100_dump_dma_regs(void __iomem *ioaddr)
|
||||
{
|
||||
int i;
|
||||
|
||||
CHIP_DBG(KERN_DEBUG "DWMAC 100 DMA CSR\n");
|
||||
for (i = 0; i < 9; i++)
|
||||
pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
|
||||
(DMA_BUS_MODE + i * 4),
|
||||
readl(ioaddr + DMA_BUS_MODE + i * 4));
|
||||
CHIP_DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n",
|
||||
DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
|
||||
CHIP_DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n",
|
||||
DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
|
||||
}
|
||||
|
||||
/* DMA controller has two counters to track the number of the missed frames. */
|
||||
static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
|
||||
void __iomem *ioaddr)
|
||||
{
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
|
||||
|
||||
if (unlikely(csr8)) {
|
||||
if (csr8 & DMA_MISSED_FRAME_OVE) {
|
||||
stats->rx_over_errors += 0x800;
|
||||
x->rx_overflow_cntr += 0x800;
|
||||
} else {
|
||||
unsigned int ove_cntr;
|
||||
ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
|
||||
stats->rx_over_errors += ove_cntr;
|
||||
x->rx_overflow_cntr += ove_cntr;
|
||||
}
|
||||
|
||||
if (csr8 & DMA_MISSED_FRAME_OVE_M) {
|
||||
stats->rx_missed_errors += 0xffff;
|
||||
x->rx_missed_cntr += 0xffff;
|
||||
} else {
|
||||
unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
|
||||
stats->rx_missed_errors += miss_f;
|
||||
x->rx_missed_cntr += miss_f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_dma_ops dwmac100_dma_ops = {
|
||||
.init = dwmac100_dma_init,
|
||||
.dump_regs = dwmac100_dump_dma_regs,
|
||||
.dma_mode = dwmac100_dma_operation_mode,
|
||||
.dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
|
||||
.enable_dma_transmission = dwmac_enable_dma_transmission,
|
||||
.enable_dma_irq = dwmac_enable_dma_irq,
|
||||
.disable_dma_irq = dwmac_disable_dma_irq,
|
||||
.start_tx = dwmac_dma_start_tx,
|
||||
.stop_tx = dwmac_dma_stop_tx,
|
||||
.start_rx = dwmac_dma_start_rx,
|
||||
.stop_rx = dwmac_dma_stop_rx,
|
||||
.dma_interrupt = dwmac_dma_interrupt,
|
||||
};
|
||||
117
drivers/net/ethernet/rockchip/gmac/dwmac_dma.h
Executable file
117
drivers/net/ethernet/rockchip/gmac/dwmac_dma.h
Executable file
@@ -0,0 +1,117 @@
|
||||
/*******************************************************************************
|
||||
DWMAC DMA Header file.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __DWMAC_DMA_H__
|
||||
#define __DWMAC_DMA_H__
|
||||
|
||||
/* DMA CRS Control and Status Register Mapping */
|
||||
#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
|
||||
#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
|
||||
#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */
|
||||
#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */
|
||||
#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */
|
||||
#define DMA_STATUS 0x00001014 /* Status Register */
|
||||
#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */
|
||||
#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */
|
||||
#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
|
||||
/* Rx watchdog register */
|
||||
#define DMA_RX_WATCHDOG 0x00001024
|
||||
/* AXI Bus Mode */
|
||||
#define DMA_AXI_BUS_MODE 0x00001028
|
||||
#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
|
||||
#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
|
||||
#define DMA_HW_FEATURE 0x00001058 /* HW Feature Register */
|
||||
|
||||
/* DMA Control register defines */
|
||||
#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
|
||||
#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
|
||||
|
||||
/* DMA Normal interrupt */
|
||||
#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */
|
||||
#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */
|
||||
#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */
|
||||
#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */
|
||||
#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */
|
||||
|
||||
#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
|
||||
DMA_INTR_ENA_TIE)
|
||||
|
||||
/* DMA Abnormal interrupt */
|
||||
#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */
|
||||
#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */
|
||||
#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */
|
||||
#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */
|
||||
#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */
|
||||
#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */
|
||||
#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */
|
||||
#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */
|
||||
#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */
|
||||
#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */
|
||||
|
||||
#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
|
||||
DMA_INTR_ENA_UNE)
|
||||
|
||||
/* DMA default interrupt mask */
|
||||
#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
|
||||
|
||||
/* DMA Status register defines */
|
||||
#define DMA_STATUS_GLPII 0x40000000 /* GMAC LPI interrupt */
|
||||
#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */
|
||||
#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
|
||||
#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
|
||||
#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
|
||||
#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
|
||||
#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
|
||||
#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
|
||||
#define DMA_STATUS_TS_SHIFT 20
|
||||
#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
|
||||
#define DMA_STATUS_RS_SHIFT 17
|
||||
#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
|
||||
#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
|
||||
#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
|
||||
#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
|
||||
#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
|
||||
#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
|
||||
#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
|
||||
#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
|
||||
#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
|
||||
#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
|
||||
#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
|
||||
#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
|
||||
#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
|
||||
#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
|
||||
#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
|
||||
#define DMA_CONTROL_FTF 0x00100000 /* Flush transmit FIFO */
|
||||
|
||||
extern void dwmac_enable_dma_transmission(void __iomem *ioaddr);
|
||||
extern void dwmac_enable_dma_irq(void __iomem *ioaddr);
|
||||
extern void dwmac_disable_dma_irq(void __iomem *ioaddr);
|
||||
extern void dwmac_dma_start_tx(void __iomem *ioaddr);
|
||||
extern void dwmac_dma_stop_tx(void __iomem *ioaddr);
|
||||
extern void dwmac_dma_start_rx(void __iomem *ioaddr);
|
||||
extern void dwmac_dma_stop_rx(void __iomem *ioaddr);
|
||||
extern int dwmac_dma_interrupt(void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x);
|
||||
|
||||
#endif /* __DWMAC_DMA_H__ */
|
||||
289
drivers/net/ethernet/rockchip/gmac/dwmac_lib.c
Executable file
289
drivers/net/ethernet/rockchip/gmac/dwmac_lib.c
Executable file
@@ -0,0 +1,289 @@
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include "common.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
#undef DWMAC_DMA_DEBUG
|
||||
#ifdef DWMAC_DMA_DEBUG
|
||||
#define DWMAC_LIB_DBG(fmt, args...) printk(fmt, ## args)
|
||||
#else
|
||||
#define DWMAC_LIB_DBG(fmt, args...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define GMAC_HI_REG_AE 0x80000000
|
||||
|
||||
/* CSR1 enables the transmit DMA to check for new descriptor */
|
||||
void dwmac_enable_dma_transmission(void __iomem *ioaddr)
|
||||
{
|
||||
writel(1, ioaddr + DMA_XMT_POLL_DEMAND);
|
||||
}
|
||||
|
||||
void dwmac_enable_dma_irq(void __iomem *ioaddr)
|
||||
{
|
||||
writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
|
||||
}
|
||||
|
||||
void dwmac_disable_dma_irq(void __iomem *ioaddr)
|
||||
{
|
||||
writel(0, ioaddr + DMA_INTR_ENA);
|
||||
}
|
||||
|
||||
void dwmac_dma_start_tx(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CONTROL);
|
||||
value |= DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
void dwmac_dma_stop_tx(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CONTROL);
|
||||
value &= ~DMA_CONTROL_ST;
|
||||
writel(value, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
void dwmac_dma_start_rx(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CONTROL);
|
||||
value |= DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
void dwmac_dma_stop_rx(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + DMA_CONTROL);
|
||||
value &= ~DMA_CONTROL_SR;
|
||||
writel(value, ioaddr + DMA_CONTROL);
|
||||
}
|
||||
|
||||
#ifdef DWMAC_DMA_DEBUG
|
||||
static void show_tx_process_state(unsigned int status)
|
||||
{
|
||||
unsigned int state;
|
||||
state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
pr_info("- TX (Stopped): Reset or Stop command\n");
|
||||
break;
|
||||
case 1:
|
||||
pr_info("- TX (Running):Fetching the Tx desc\n");
|
||||
break;
|
||||
case 2:
|
||||
pr_info("- TX (Running): Waiting for end of tx\n");
|
||||
break;
|
||||
case 3:
|
||||
pr_info("- TX (Running): Reading the data "
|
||||
"and queuing the data into the Tx buf\n");
|
||||
break;
|
||||
case 6:
|
||||
pr_info("- TX (Suspended): Tx Buff Underflow "
|
||||
"or an unavailable Transmit descriptor\n");
|
||||
break;
|
||||
case 7:
|
||||
pr_info("- TX (Running): Closing Tx descriptor\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void show_rx_process_state(unsigned int status)
|
||||
{
|
||||
unsigned int state;
|
||||
state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
|
||||
|
||||
switch (state) {
|
||||
case 0:
|
||||
pr_info("- RX (Stopped): Reset or Stop command\n");
|
||||
break;
|
||||
case 1:
|
||||
pr_info("- RX (Running): Fetching the Rx desc\n");
|
||||
break;
|
||||
case 2:
|
||||
pr_info("- RX (Running):Checking for end of pkt\n");
|
||||
break;
|
||||
case 3:
|
||||
pr_info("- RX (Running): Waiting for Rx pkt\n");
|
||||
break;
|
||||
case 4:
|
||||
pr_info("- RX (Suspended): Unavailable Rx buf\n");
|
||||
break;
|
||||
case 5:
|
||||
pr_info("- RX (Running): Closing Rx descriptor\n");
|
||||
break;
|
||||
case 6:
|
||||
pr_info("- RX(Running): Flushing the current frame"
|
||||
" from the Rx buf\n");
|
||||
break;
|
||||
case 7:
|
||||
pr_info("- RX (Running): Queuing the Rx frame"
|
||||
" from the Rx buf into memory\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int dwmac_dma_interrupt(void __iomem *ioaddr,
|
||||
struct stmmac_extra_stats *x)
|
||||
{
|
||||
int ret = 0;
|
||||
/* read the status register (CSR5) */
|
||||
u32 intr_status = readl(ioaddr + DMA_STATUS);
|
||||
|
||||
DWMAC_LIB_DBG(KERN_INFO "%s: [CSR5: 0x%08x]\n", __func__, intr_status);
|
||||
#ifdef DWMAC_DMA_DEBUG
|
||||
/* It displays the DMA process states (CSR5 register) */
|
||||
show_tx_process_state(intr_status);
|
||||
show_rx_process_state(intr_status);
|
||||
#endif
|
||||
/* ABNORMAL interrupts */
|
||||
if (unlikely(intr_status & DMA_STATUS_AIS)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "CSR5[15] DMA ABNORMAL IRQ: ");
|
||||
if (unlikely(intr_status & DMA_STATUS_UNF)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "transmit underflow\n");
|
||||
ret = tx_hard_error_bump_tc;
|
||||
x->tx_undeflow_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_TJT)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "transmit jabber\n");
|
||||
x->tx_jabber_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_OVF)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "recv overflow\n");
|
||||
x->rx_overflow_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_RU)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "receive buffer unavailable\n");
|
||||
x->rx_buf_unav_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_RPS)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "receive process stopped\n");
|
||||
x->rx_process_stopped_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_RWT)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "receive watchdog\n");
|
||||
x->rx_watchdog_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_ETI)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "transmit early interrupt\n");
|
||||
x->tx_early_irq++;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_TPS)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "transmit process stopped\n");
|
||||
x->tx_process_stopped_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_FBI)) {
|
||||
DWMAC_LIB_DBG(KERN_INFO "fatal bus error\n");
|
||||
x->fatal_bus_error_irq++;
|
||||
ret = tx_hard_error;
|
||||
}
|
||||
}
|
||||
/* TX/RX NORMAL interrupts */
|
||||
if (likely(intr_status & DMA_STATUS_NIS)) {
|
||||
x->normal_irq_n++;
|
||||
if (likely(intr_status & DMA_STATUS_RI)) {
|
||||
u32 value = readl(ioaddr + DMA_INTR_ENA);
|
||||
/* to schedule NAPI on real RIE event. */
|
||||
if (likely(value & DMA_INTR_ENA_RIE)) {
|
||||
x->rx_normal_irq_n++;
|
||||
ret |= handle_rx;
|
||||
}
|
||||
}
|
||||
if (likely(intr_status & DMA_STATUS_TI)) {
|
||||
x->tx_normal_irq_n++;
|
||||
ret |= handle_tx;
|
||||
}
|
||||
if (unlikely(intr_status & DMA_STATUS_ERI))
|
||||
x->rx_early_irq++;
|
||||
}
|
||||
/* Optional hardware blocks, interrupts should be disabled */
|
||||
if (unlikely(intr_status &
|
||||
(DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
|
||||
pr_info("%s: unexpected status %08x\n", __func__, intr_status);
|
||||
|
||||
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
|
||||
writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
|
||||
|
||||
DWMAC_LIB_DBG(KERN_INFO "\n\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr)
|
||||
{
|
||||
u32 csr6 = readl(ioaddr + DMA_CONTROL);
|
||||
writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
|
||||
|
||||
do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
|
||||
}
|
||||
|
||||
void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned long data;
|
||||
|
||||
data = (addr[5] << 8) | addr[4];
|
||||
/* For MAC Addr registers se have to set the Address Enable (AE)
|
||||
* bit that has no effect on the High Reg 0 where the bit 31 (MO)
|
||||
* is RO.
|
||||
*/
|
||||
writel(data | GMAC_HI_REG_AE, ioaddr + high);
|
||||
data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
|
||||
writel(data, ioaddr + low);
|
||||
}
|
||||
|
||||
/* Enable disable MAC RX/TX */
|
||||
void stmmac_set_mac(void __iomem *ioaddr, bool enable)
|
||||
{
|
||||
u32 value = readl(ioaddr + MAC_CTRL_REG);
|
||||
|
||||
if (enable)
|
||||
value |= MAC_RNABLE_RX | MAC_ENABLE_TX;
|
||||
else
|
||||
value &= ~(MAC_ENABLE_TX | MAC_RNABLE_RX);
|
||||
|
||||
writel(value, ioaddr + MAC_CTRL_REG);
|
||||
}
|
||||
|
||||
void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
|
||||
unsigned int high, unsigned int low)
|
||||
{
|
||||
unsigned int hi_addr, lo_addr;
|
||||
|
||||
/* Read the MAC address from the hardware */
|
||||
hi_addr = readl(ioaddr + high);
|
||||
lo_addr = readl(ioaddr + low);
|
||||
|
||||
/* Extract the MAC address from the high and low words */
|
||||
addr[0] = lo_addr & 0xff;
|
||||
addr[1] = (lo_addr >> 8) & 0xff;
|
||||
addr[2] = (lo_addr >> 16) & 0xff;
|
||||
addr[3] = (lo_addr >> 24) & 0xff;
|
||||
addr[4] = hi_addr & 0xff;
|
||||
addr[5] = (hi_addr >> 8) & 0xff;
|
||||
}
|
||||
|
||||
445
drivers/net/ethernet/rockchip/gmac/enh_desc.c
Executable file
445
drivers/net/ethernet/rockchip/gmac/enh_desc.c
Executable file
@@ -0,0 +1,445 @@
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the enhanced descriptors.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common.h"
|
||||
#include "descs_com.h"
|
||||
|
||||
static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr)
|
||||
{
|
||||
int ret = 0;
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
|
||||
if (unlikely(p->des01.etx.error_summary)) {
|
||||
CHIP_DBG(KERN_ERR "GMAC TX error... 0x%08x\n", p->des01.etx);
|
||||
if (unlikely(p->des01.etx.jabber_timeout)) {
|
||||
CHIP_DBG(KERN_ERR "\tjabber_timeout error\n");
|
||||
x->tx_jabber++;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.etx.frame_flushed)) {
|
||||
CHIP_DBG(KERN_ERR "\tframe_flushed error\n");
|
||||
x->tx_frame_flushed++;
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.etx.loss_carrier)) {
|
||||
CHIP_DBG(KERN_ERR "\tloss_carrier error\n");
|
||||
x->tx_losscarrier++;
|
||||
stats->tx_carrier_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.etx.no_carrier)) {
|
||||
CHIP_DBG(KERN_ERR "\tno_carrier error\n");
|
||||
x->tx_carrier++;
|
||||
stats->tx_carrier_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.etx.late_collision)) {
|
||||
CHIP_DBG(KERN_ERR "\tlate_collision error\n");
|
||||
stats->collisions += p->des01.etx.collision_count;
|
||||
}
|
||||
if (unlikely(p->des01.etx.excessive_collisions)) {
|
||||
CHIP_DBG(KERN_ERR "\texcessive_collisions\n");
|
||||
stats->collisions += p->des01.etx.collision_count;
|
||||
}
|
||||
if (unlikely(p->des01.etx.excessive_deferral)) {
|
||||
CHIP_DBG(KERN_INFO "\texcessive tx_deferral\n");
|
||||
x->tx_deferred++;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.etx.underflow_error)) {
|
||||
CHIP_DBG(KERN_ERR "\tunderflow error\n");
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
x->tx_underflow++;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.etx.ip_header_error)) {
|
||||
CHIP_DBG(KERN_ERR "\tTX IP header csum error\n");
|
||||
x->tx_ip_header_error++;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.etx.payload_error)) {
|
||||
CHIP_DBG(KERN_ERR "\tAddr/Payload csum error\n");
|
||||
x->tx_payload_error++;
|
||||
dwmac_dma_flush_tx_fifo(ioaddr);
|
||||
}
|
||||
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.etx.deferred)) {
|
||||
CHIP_DBG(KERN_INFO "GMAC TX status: tx deferred\n");
|
||||
x->tx_deferred++;
|
||||
}
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (p->des01.etx.vlan_frame) {
|
||||
CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
|
||||
x->tx_vlan++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.etx.buffer1_size;
|
||||
}
|
||||
|
||||
static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
|
||||
{
|
||||
int ret = good_frame;
|
||||
u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
|
||||
|
||||
/* bits 5 7 0 | Frame status
|
||||
* ----------------------------------------------------------
|
||||
* 0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
|
||||
* 1 0 0 | IPv4/6 No CSUM errorS.
|
||||
* 1 0 1 | IPv4/6 CSUM PAYLOAD error
|
||||
* 1 1 0 | IPv4/6 CSUM IP HR error
|
||||
* 1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
|
||||
* 0 0 1 | IPv4/6 unsupported IP PAYLOAD
|
||||
* 0 1 1 | COE bypassed.. no IPv4/6 frame
|
||||
* 0 1 0 | Reserved.
|
||||
*/
|
||||
if (status == 0x0) {
|
||||
CHIP_DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
|
||||
ret = llc_snap;
|
||||
} else if (status == 0x4) {
|
||||
CHIP_DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
|
||||
ret = good_frame;
|
||||
} else if (status == 0x5) {
|
||||
CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Payload Error.\n");
|
||||
ret = csum_none;
|
||||
} else if (status == 0x6) {
|
||||
CHIP_DBG(KERN_ERR "RX Des0 status: IPv4/6 Header Error.\n");
|
||||
ret = csum_none;
|
||||
} else if (status == 0x7) {
|
||||
CHIP_DBG(KERN_ERR
|
||||
"RX Des0 status: IPv4/6 Header and Payload Error.\n");
|
||||
ret = csum_none;
|
||||
} else if (status == 0x1) {
|
||||
CHIP_DBG(KERN_ERR
|
||||
"RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n");
|
||||
ret = discard_frame;
|
||||
} else if (status == 0x3) {
|
||||
CHIP_DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n");
|
||||
ret = discard_frame;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_extended_desc *p)
|
||||
{
|
||||
if (unlikely(p->basic.des01.erx.rx_mac_addr)) {
|
||||
if (p->des4.erx.ip_hdr_err)
|
||||
x->ip_hdr_err++;
|
||||
if (p->des4.erx.ip_payload_err)
|
||||
x->ip_payload_err++;
|
||||
if (p->des4.erx.ip_csum_bypassed)
|
||||
x->ip_csum_bypassed++;
|
||||
if (p->des4.erx.ipv4_pkt_rcvd)
|
||||
x->ipv4_pkt_rcvd++;
|
||||
if (p->des4.erx.ipv6_pkt_rcvd)
|
||||
x->ipv6_pkt_rcvd++;
|
||||
if (p->des4.erx.msg_type == RDES_EXT_SYNC)
|
||||
x->rx_msg_type_sync++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_FOLLOW_UP)
|
||||
x->rx_msg_type_follow_up++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
|
||||
x->rx_msg_type_delay_req++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_DELAY_RESP)
|
||||
x->rx_msg_type_delay_resp++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_DELAY_REQ)
|
||||
x->rx_msg_type_pdelay_req++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_RESP)
|
||||
x->rx_msg_type_pdelay_resp++;
|
||||
else if (p->des4.erx.msg_type == RDES_EXT_PDELAY_FOLLOW_UP)
|
||||
x->rx_msg_type_pdelay_follow_up++;
|
||||
else
|
||||
x->rx_msg_type_ext_no_ptp++;
|
||||
if (p->des4.erx.ptp_frame_type)
|
||||
x->ptp_frame_type++;
|
||||
if (p->des4.erx.ptp_ver)
|
||||
x->ptp_ver++;
|
||||
if (p->des4.erx.timestamp_dropped)
|
||||
x->timestamp_dropped++;
|
||||
if (p->des4.erx.av_pkt_rcvd)
|
||||
x->av_pkt_rcvd++;
|
||||
if (p->des4.erx.av_tagged_pkt_rcvd)
|
||||
x->av_tagged_pkt_rcvd++;
|
||||
if (p->des4.erx.vlan_tag_priority_val)
|
||||
x->vlan_tag_priority_val++;
|
||||
if (p->des4.erx.l3_filter_match)
|
||||
x->l3_filter_match++;
|
||||
if (p->des4.erx.l4_filter_match)
|
||||
x->l4_filter_match++;
|
||||
if (p->des4.erx.l3_l4_filter_no_match)
|
||||
x->l3_l4_filter_no_match++;
|
||||
}
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
int ret = good_frame;
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
|
||||
if (unlikely(p->des01.erx.error_summary)) {
|
||||
CHIP_DBG(KERN_ERR "GMAC RX Error Summary 0x%08x\n",
|
||||
p->des01.erx);
|
||||
if (unlikely(p->des01.erx.descriptor_error)) {
|
||||
CHIP_DBG(KERN_ERR "\tdescriptor error\n");
|
||||
x->rx_desc++;
|
||||
stats->rx_length_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.erx.overflow_error)) {
|
||||
CHIP_DBG(KERN_ERR "\toverflow error\n");
|
||||
x->rx_gmac_overflow++;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.erx.ipc_csum_error))
|
||||
CHIP_DBG(KERN_ERR "\tIPC Csum Error/Giant frame\n");
|
||||
|
||||
if (unlikely(p->des01.erx.late_collision)) {
|
||||
CHIP_DBG(KERN_ERR "\tlate_collision error\n");
|
||||
stats->collisions++;
|
||||
stats->collisions++;
|
||||
}
|
||||
if (unlikely(p->des01.erx.receive_watchdog)) {
|
||||
CHIP_DBG(KERN_ERR "\treceive_watchdog error\n");
|
||||
x->rx_watchdog++;
|
||||
}
|
||||
if (unlikely(p->des01.erx.error_gmii)) {
|
||||
CHIP_DBG(KERN_ERR "\tReceive Error\n");
|
||||
x->rx_mii++;
|
||||
}
|
||||
if (unlikely(p->des01.erx.crc_error)) {
|
||||
CHIP_DBG(KERN_ERR "\tCRC error\n");
|
||||
x->rx_crc++;
|
||||
stats->rx_crc_errors++;
|
||||
}
|
||||
ret = discard_frame;
|
||||
}
|
||||
|
||||
/* After a payload csum error, the ES bit is set.
|
||||
* It doesn't match with the information reported into the databook.
|
||||
* At any rate, we need to understand if the CSUM hw computation is ok
|
||||
* and report this info to the upper layers. */
|
||||
ret = enh_desc_coe_rdes0(p->des01.erx.ipc_csum_error,
|
||||
p->des01.erx.frame_type, p->des01.erx.rx_mac_addr);
|
||||
|
||||
if (unlikely(p->des01.erx.dribbling)) {
|
||||
CHIP_DBG(KERN_ERR "GMAC RX: dribbling error\n");
|
||||
x->dribbling_bit++;
|
||||
}
|
||||
if (unlikely(p->des01.erx.sa_filter_fail)) {
|
||||
CHIP_DBG(KERN_ERR "GMAC RX : Source Address filter fail\n");
|
||||
x->sa_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(p->des01.erx.da_filter_fail)) {
|
||||
CHIP_DBG(KERN_ERR "GMAC RX : Dest Address filter fail\n");
|
||||
x->da_rx_filter_fail++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(p->des01.erx.length_error)) {
|
||||
CHIP_DBG(KERN_ERR "GMAC RX: length_error error\n");
|
||||
x->rx_length++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (p->des01.erx.vlan_tag) {
|
||||
CHIP_DBG(KERN_INFO "GMAC RX: VLAN frame tagged\n");
|
||||
x->rx_vlan++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
|
||||
int mode, int end)
|
||||
{
|
||||
p->des01.erx.own = 1;
|
||||
p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ehn_desc_rx_set_on_chain(p, end);
|
||||
else
|
||||
ehn_desc_rx_set_on_ring(p, end);
|
||||
|
||||
if (disable_rx_ic)
|
||||
p->des01.erx.disable_ic = 1;
|
||||
}
|
||||
|
||||
static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des01.etx.own = 0;
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ehn_desc_tx_set_on_chain(p, end);
|
||||
else
|
||||
ehn_desc_tx_set_on_ring(p, end);
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.etx.own;
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_owner(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.erx.own;
|
||||
}
|
||||
|
||||
static void enh_desc_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des01.etx.own = 1;
|
||||
}
|
||||
|
||||
static void enh_desc_set_rx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des01.erx.own = 1;
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.etx.last_segment;
|
||||
}
|
||||
|
||||
static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
int ter = p->des01.etx.end_ring;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_desc_end_tx_desc_on_chain(p, ter);
|
||||
else
|
||||
enh_desc_end_tx_desc_on_ring(p, ter);
|
||||
}
|
||||
|
||||
static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
int csum_flag, int mode)
|
||||
{
|
||||
p->des01.etx.first_segment = is_fs;
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
enh_set_tx_desc_len_on_chain(p, len);
|
||||
else
|
||||
enh_set_tx_desc_len_on_ring(p, len);
|
||||
|
||||
if (likely(csum_flag))
|
||||
p->des01.etx.checksum_insertion = cic_full;
|
||||
}
|
||||
|
||||
static void enh_desc_clear_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des01.etx.interrupt = 0;
|
||||
}
|
||||
|
||||
static void enh_desc_close_tx_desc(struct dma_desc *p)
|
||||
{
|
||||
p->des01.etx.last_segment = 1;
|
||||
p->des01.etx.interrupt = 1;
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
|
||||
{
|
||||
/* The type-1 checksum offload engines append the checksum at
|
||||
* the end of frame and the two bytes of checksum are added in
|
||||
* the length.
|
||||
* Adjust for that in the framelen for type-1 checksum offload
|
||||
* engines. */
|
||||
if (rx_coe_type == STMMAC_RX_COE_TYPE1)
|
||||
return p->des01.erx.frame_length - 2;
|
||||
else
|
||||
return p->des01.erx.frame_length;
|
||||
}
|
||||
|
||||
static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des01.etx.time_stamp_enable = 1;
|
||||
}
|
||||
|
||||
static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.etx.time_stamp_status;
|
||||
}
|
||||
|
||||
static u64 enh_desc_get_timestamp(void *desc, u32 ats)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
if (ats) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
|
||||
ns = p->des6;
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += p->des7 * 1000000000ULL;
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
ns = p->des2;
|
||||
ns += p->des3 * 1000000000ULL;
|
||||
}
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
static int enh_desc_get_rx_timestamp_status(void *desc, u32 ats)
|
||||
{
|
||||
if (ats) {
|
||||
struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
|
||||
return p->basic.des01.erx.ipc_csum_error;
|
||||
} else {
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
|
||||
/* timestamp is corrupted, hence don't store it */
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops enh_desc_ops = {
|
||||
.tx_status = enh_desc_get_tx_status,
|
||||
.rx_status = enh_desc_get_rx_status,
|
||||
.get_tx_len = enh_desc_get_tx_len,
|
||||
.init_rx_desc = enh_desc_init_rx_desc,
|
||||
.init_tx_desc = enh_desc_init_tx_desc,
|
||||
.get_tx_owner = enh_desc_get_tx_owner,
|
||||
.get_rx_owner = enh_desc_get_rx_owner,
|
||||
.release_tx_desc = enh_desc_release_tx_desc,
|
||||
.prepare_tx_desc = enh_desc_prepare_tx_desc,
|
||||
.clear_tx_ic = enh_desc_clear_tx_ic,
|
||||
.close_tx_desc = enh_desc_close_tx_desc,
|
||||
.get_tx_ls = enh_desc_get_tx_ls,
|
||||
.set_tx_owner = enh_desc_set_tx_owner,
|
||||
.set_rx_owner = enh_desc_set_rx_owner,
|
||||
.get_rx_frame_len = enh_desc_get_rx_frame_len,
|
||||
.rx_extended_status = enh_desc_get_ext_status,
|
||||
.enable_tx_timestamp = enh_desc_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
|
||||
.get_timestamp = enh_desc_get_timestamp,
|
||||
.get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
|
||||
};
|
||||
BIN
drivers/net/ethernet/rockchip/gmac/gmac.IAB
Executable file
BIN
drivers/net/ethernet/rockchip/gmac/gmac.IAB
Executable file
Binary file not shown.
BIN
drivers/net/ethernet/rockchip/gmac/gmac.IAD
Executable file
BIN
drivers/net/ethernet/rockchip/gmac/gmac.IAD
Executable file
Binary file not shown.
BIN
drivers/net/ethernet/rockchip/gmac/gmac.IMB
Executable file
BIN
drivers/net/ethernet/rockchip/gmac/gmac.IMB
Executable file
Binary file not shown.
BIN
drivers/net/ethernet/rockchip/gmac/gmac.IMD
Executable file
BIN
drivers/net/ethernet/rockchip/gmac/gmac.IMD
Executable file
Binary file not shown.
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PFI
Executable file
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PFI
Executable file
Binary file not shown.
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PO
Executable file
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PO
Executable file
Binary file not shown.
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PR
Executable file
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PR
Executable file
Binary file not shown.
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PRI
Executable file
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PRI
Executable file
Binary file not shown.
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PS
Executable file
BIN
drivers/net/ethernet/rockchip/gmac/gmac.PS
Executable file
Binary file not shown.
1
drivers/net/ethernet/rockchip/gmac/gmac.SearchResults
Executable file
1
drivers/net/ethernet/rockchip/gmac/gmac.SearchResults
Executable file
@@ -0,0 +1 @@
|
||||
---- STMMAC_DEBUG_FS Matches (0 in 0 files) ----
|
||||
135
drivers/net/ethernet/rockchip/gmac/mmc.h
Executable file
135
drivers/net/ethernet/rockchip/gmac/mmc.h
Executable file
@@ -0,0 +1,135 @@
|
||||
/*******************************************************************************
|
||||
MMC Header file
|
||||
|
||||
Copyright (C) 2011 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __MMC_H__
|
||||
#define __MMC_H__
|
||||
|
||||
/* MMC control register */
|
||||
/* When set, all counter are reset */
|
||||
#define MMC_CNTRL_COUNTER_RESET 0x1
|
||||
/* When set, do not roll over zero after reaching the max value*/
|
||||
#define MMC_CNTRL_COUNTER_STOP_ROLLOVER 0x2
|
||||
#define MMC_CNTRL_RESET_ON_READ 0x4 /* Reset after reading */
|
||||
#define MMC_CNTRL_COUNTER_FREEZER 0x8 /* Freeze counter values to the
|
||||
* current value.*/
|
||||
#define MMC_CNTRL_PRESET 0x10
|
||||
#define MMC_CNTRL_FULL_HALF_PRESET 0x20
|
||||
struct stmmac_counters {
|
||||
unsigned int mmc_tx_octetcount_gb;
|
||||
unsigned int mmc_tx_framecount_gb;
|
||||
unsigned int mmc_tx_broadcastframe_g;
|
||||
unsigned int mmc_tx_multicastframe_g;
|
||||
unsigned int mmc_tx_64_octets_gb;
|
||||
unsigned int mmc_tx_65_to_127_octets_gb;
|
||||
unsigned int mmc_tx_128_to_255_octets_gb;
|
||||
unsigned int mmc_tx_256_to_511_octets_gb;
|
||||
unsigned int mmc_tx_512_to_1023_octets_gb;
|
||||
unsigned int mmc_tx_1024_to_max_octets_gb;
|
||||
unsigned int mmc_tx_unicast_gb;
|
||||
unsigned int mmc_tx_multicast_gb;
|
||||
unsigned int mmc_tx_broadcast_gb;
|
||||
unsigned int mmc_tx_underflow_error;
|
||||
unsigned int mmc_tx_singlecol_g;
|
||||
unsigned int mmc_tx_multicol_g;
|
||||
unsigned int mmc_tx_deferred;
|
||||
unsigned int mmc_tx_latecol;
|
||||
unsigned int mmc_tx_exesscol;
|
||||
unsigned int mmc_tx_carrier_error;
|
||||
unsigned int mmc_tx_octetcount_g;
|
||||
unsigned int mmc_tx_framecount_g;
|
||||
unsigned int mmc_tx_excessdef;
|
||||
unsigned int mmc_tx_pause_frame;
|
||||
unsigned int mmc_tx_vlan_frame_g;
|
||||
|
||||
/* MMC RX counter registers */
|
||||
unsigned int mmc_rx_framecount_gb;
|
||||
unsigned int mmc_rx_octetcount_gb;
|
||||
unsigned int mmc_rx_octetcount_g;
|
||||
unsigned int mmc_rx_broadcastframe_g;
|
||||
unsigned int mmc_rx_multicastframe_g;
|
||||
unsigned int mmc_rx_crc_errror;
|
||||
unsigned int mmc_rx_align_error;
|
||||
unsigned int mmc_rx_run_error;
|
||||
unsigned int mmc_rx_jabber_error;
|
||||
unsigned int mmc_rx_undersize_g;
|
||||
unsigned int mmc_rx_oversize_g;
|
||||
unsigned int mmc_rx_64_octets_gb;
|
||||
unsigned int mmc_rx_65_to_127_octets_gb;
|
||||
unsigned int mmc_rx_128_to_255_octets_gb;
|
||||
unsigned int mmc_rx_256_to_511_octets_gb;
|
||||
unsigned int mmc_rx_512_to_1023_octets_gb;
|
||||
unsigned int mmc_rx_1024_to_max_octets_gb;
|
||||
unsigned int mmc_rx_unicast_g;
|
||||
unsigned int mmc_rx_length_error;
|
||||
unsigned int mmc_rx_autofrangetype;
|
||||
unsigned int mmc_rx_pause_frames;
|
||||
unsigned int mmc_rx_fifo_overflow;
|
||||
unsigned int mmc_rx_vlan_frames_gb;
|
||||
unsigned int mmc_rx_watchdog_error;
|
||||
/* IPC */
|
||||
unsigned int mmc_rx_ipc_intr_mask;
|
||||
unsigned int mmc_rx_ipc_intr;
|
||||
/* IPv4 */
|
||||
unsigned int mmc_rx_ipv4_gd;
|
||||
unsigned int mmc_rx_ipv4_hderr;
|
||||
unsigned int mmc_rx_ipv4_nopay;
|
||||
unsigned int mmc_rx_ipv4_frag;
|
||||
unsigned int mmc_rx_ipv4_udsbl;
|
||||
|
||||
unsigned int mmc_rx_ipv4_gd_octets;
|
||||
unsigned int mmc_rx_ipv4_hderr_octets;
|
||||
unsigned int mmc_rx_ipv4_nopay_octets;
|
||||
unsigned int mmc_rx_ipv4_frag_octets;
|
||||
unsigned int mmc_rx_ipv4_udsbl_octets;
|
||||
|
||||
/* IPV6 */
|
||||
unsigned int mmc_rx_ipv6_gd_octets;
|
||||
unsigned int mmc_rx_ipv6_hderr_octets;
|
||||
unsigned int mmc_rx_ipv6_nopay_octets;
|
||||
|
||||
unsigned int mmc_rx_ipv6_gd;
|
||||
unsigned int mmc_rx_ipv6_hderr;
|
||||
unsigned int mmc_rx_ipv6_nopay;
|
||||
|
||||
/* Protocols */
|
||||
unsigned int mmc_rx_udp_gd;
|
||||
unsigned int mmc_rx_udp_err;
|
||||
unsigned int mmc_rx_tcp_gd;
|
||||
unsigned int mmc_rx_tcp_err;
|
||||
unsigned int mmc_rx_icmp_gd;
|
||||
unsigned int mmc_rx_icmp_err;
|
||||
|
||||
unsigned int mmc_rx_udp_gd_octets;
|
||||
unsigned int mmc_rx_udp_err_octets;
|
||||
unsigned int mmc_rx_tcp_gd_octets;
|
||||
unsigned int mmc_rx_tcp_err_octets;
|
||||
unsigned int mmc_rx_icmp_gd_octets;
|
||||
unsigned int mmc_rx_icmp_err_octets;
|
||||
};
|
||||
|
||||
extern void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode);
|
||||
extern void dwmac_mmc_intr_all_mask(void __iomem *ioaddr);
|
||||
extern void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc);
|
||||
|
||||
#endif /* __MMC_H__ */
|
||||
267
drivers/net/ethernet/rockchip/gmac/mmc_core.c
Executable file
267
drivers/net/ethernet/rockchip/gmac/mmc_core.c
Executable file
@@ -0,0 +1,267 @@
|
||||
/*******************************************************************************
|
||||
DWMAC Management Counters
|
||||
|
||||
Copyright (C) 2011 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include "mmc.h"
|
||||
|
||||
/* MAC Management Counters register offset */
|
||||
|
||||
#define MMC_CNTRL 0x00000100 /* MMC Control */
|
||||
#define MMC_RX_INTR 0x00000104 /* MMC RX Interrupt */
|
||||
#define MMC_TX_INTR 0x00000108 /* MMC TX Interrupt */
|
||||
#define MMC_RX_INTR_MASK 0x0000010c /* MMC Interrupt Mask */
|
||||
#define MMC_TX_INTR_MASK 0x00000110 /* MMC Interrupt Mask */
|
||||
#define MMC_DEFAULT_MASK 0xffffffff
|
||||
|
||||
/* MMC TX counter registers */
|
||||
|
||||
/* Note:
|
||||
* _GB register stands for good and bad frames
|
||||
* _G is for good only.
|
||||
*/
|
||||
#define MMC_TX_OCTETCOUNT_GB 0x00000114
|
||||
#define MMC_TX_FRAMECOUNT_GB 0x00000118
|
||||
#define MMC_TX_BROADCASTFRAME_G 0x0000011c
|
||||
#define MMC_TX_MULTICASTFRAME_G 0x00000120
|
||||
#define MMC_TX_64_OCTETS_GB 0x00000124
|
||||
#define MMC_TX_65_TO_127_OCTETS_GB 0x00000128
|
||||
#define MMC_TX_128_TO_255_OCTETS_GB 0x0000012c
|
||||
#define MMC_TX_256_TO_511_OCTETS_GB 0x00000130
|
||||
#define MMC_TX_512_TO_1023_OCTETS_GB 0x00000134
|
||||
#define MMC_TX_1024_TO_MAX_OCTETS_GB 0x00000138
|
||||
#define MMC_TX_UNICAST_GB 0x0000013c
|
||||
#define MMC_TX_MULTICAST_GB 0x00000140
|
||||
#define MMC_TX_BROADCAST_GB 0x00000144
|
||||
#define MMC_TX_UNDERFLOW_ERROR 0x00000148
|
||||
#define MMC_TX_SINGLECOL_G 0x0000014c
|
||||
#define MMC_TX_MULTICOL_G 0x00000150
|
||||
#define MMC_TX_DEFERRED 0x00000154
|
||||
#define MMC_TX_LATECOL 0x00000158
|
||||
#define MMC_TX_EXESSCOL 0x0000015c
|
||||
#define MMC_TX_CARRIER_ERROR 0x00000160
|
||||
#define MMC_TX_OCTETCOUNT_G 0x00000164
|
||||
#define MMC_TX_FRAMECOUNT_G 0x00000168
|
||||
#define MMC_TX_EXCESSDEF 0x0000016c
|
||||
#define MMC_TX_PAUSE_FRAME 0x00000170
|
||||
#define MMC_TX_VLAN_FRAME_G 0x00000174
|
||||
|
||||
/* MMC RX counter registers */
|
||||
#define MMC_RX_FRAMECOUNT_GB 0x00000180
|
||||
#define MMC_RX_OCTETCOUNT_GB 0x00000184
|
||||
#define MMC_RX_OCTETCOUNT_G 0x00000188
|
||||
#define MMC_RX_BROADCASTFRAME_G 0x0000018c
|
||||
#define MMC_RX_MULTICASTFRAME_G 0x00000190
|
||||
#define MMC_RX_CRC_ERRROR 0x00000194
|
||||
#define MMC_RX_ALIGN_ERROR 0x00000198
|
||||
#define MMC_RX_RUN_ERROR 0x0000019C
|
||||
#define MMC_RX_JABBER_ERROR 0x000001A0
|
||||
#define MMC_RX_UNDERSIZE_G 0x000001A4
|
||||
#define MMC_RX_OVERSIZE_G 0x000001A8
|
||||
#define MMC_RX_64_OCTETS_GB 0x000001AC
|
||||
#define MMC_RX_65_TO_127_OCTETS_GB 0x000001b0
|
||||
#define MMC_RX_128_TO_255_OCTETS_GB 0x000001b4
|
||||
#define MMC_RX_256_TO_511_OCTETS_GB 0x000001b8
|
||||
#define MMC_RX_512_TO_1023_OCTETS_GB 0x000001bc
|
||||
#define MMC_RX_1024_TO_MAX_OCTETS_GB 0x000001c0
|
||||
#define MMC_RX_UNICAST_G 0x000001c4
|
||||
#define MMC_RX_LENGTH_ERROR 0x000001c8
|
||||
#define MMC_RX_AUTOFRANGETYPE 0x000001cc
|
||||
#define MMC_RX_PAUSE_FRAMES 0x000001d0
|
||||
#define MMC_RX_FIFO_OVERFLOW 0x000001d4
|
||||
#define MMC_RX_VLAN_FRAMES_GB 0x000001d8
|
||||
#define MMC_RX_WATCHDOG_ERROR 0x000001dc
|
||||
/* IPC*/
|
||||
#define MMC_RX_IPC_INTR_MASK 0x00000200
|
||||
#define MMC_RX_IPC_INTR 0x00000208
|
||||
/* IPv4*/
|
||||
#define MMC_RX_IPV4_GD 0x00000210
|
||||
#define MMC_RX_IPV4_HDERR 0x00000214
|
||||
#define MMC_RX_IPV4_NOPAY 0x00000218
|
||||
#define MMC_RX_IPV4_FRAG 0x0000021C
|
||||
#define MMC_RX_IPV4_UDSBL 0x00000220
|
||||
|
||||
#define MMC_RX_IPV4_GD_OCTETS 0x00000250
|
||||
#define MMC_RX_IPV4_HDERR_OCTETS 0x00000254
|
||||
#define MMC_RX_IPV4_NOPAY_OCTETS 0x00000258
|
||||
#define MMC_RX_IPV4_FRAG_OCTETS 0x0000025c
|
||||
#define MMC_RX_IPV4_UDSBL_OCTETS 0x00000260
|
||||
|
||||
/* IPV6*/
|
||||
#define MMC_RX_IPV6_GD_OCTETS 0x00000264
|
||||
#define MMC_RX_IPV6_HDERR_OCTETS 0x00000268
|
||||
#define MMC_RX_IPV6_NOPAY_OCTETS 0x0000026c
|
||||
|
||||
#define MMC_RX_IPV6_GD 0x00000224
|
||||
#define MMC_RX_IPV6_HDERR 0x00000228
|
||||
#define MMC_RX_IPV6_NOPAY 0x0000022c
|
||||
|
||||
/* Protocols*/
|
||||
#define MMC_RX_UDP_GD 0x00000230
|
||||
#define MMC_RX_UDP_ERR 0x00000234
|
||||
#define MMC_RX_TCP_GD 0x00000238
|
||||
#define MMC_RX_TCP_ERR 0x0000023c
|
||||
#define MMC_RX_ICMP_GD 0x00000240
|
||||
#define MMC_RX_ICMP_ERR 0x00000244
|
||||
|
||||
#define MMC_RX_UDP_GD_OCTETS 0x00000270
|
||||
#define MMC_RX_UDP_ERR_OCTETS 0x00000274
|
||||
#define MMC_RX_TCP_GD_OCTETS 0x00000278
|
||||
#define MMC_RX_TCP_ERR_OCTETS 0x0000027c
|
||||
#define MMC_RX_ICMP_GD_OCTETS 0x00000280
|
||||
#define MMC_RX_ICMP_ERR_OCTETS 0x00000284
|
||||
|
||||
void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode)
|
||||
{
|
||||
u32 value = readl(ioaddr + MMC_CNTRL);
|
||||
|
||||
value |= (mode & 0x3F);
|
||||
|
||||
writel(value, ioaddr + MMC_CNTRL);
|
||||
|
||||
pr_debug("stmmac: MMC ctrl register (offset 0x%x): 0x%08x\n",
|
||||
MMC_CNTRL, value);
|
||||
}
|
||||
|
||||
/* To mask all all interrupts.*/
|
||||
void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
|
||||
{
|
||||
writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK);
|
||||
writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_IPC_INTR_MASK);
|
||||
}
|
||||
|
||||
/* This reads the MAC core counters (if actaully supported).
|
||||
* by default the MMC core is programmed to reset each
|
||||
* counter after a read. So all the field of the mmc struct
|
||||
* have to be incremented.
|
||||
*/
|
||||
void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc)
|
||||
{
|
||||
mmc->mmc_tx_octetcount_gb += readl(ioaddr + MMC_TX_OCTETCOUNT_GB);
|
||||
mmc->mmc_tx_framecount_gb += readl(ioaddr + MMC_TX_FRAMECOUNT_GB);
|
||||
mmc->mmc_tx_broadcastframe_g += readl(ioaddr + MMC_TX_BROADCASTFRAME_G);
|
||||
mmc->mmc_tx_multicastframe_g += readl(ioaddr + MMC_TX_MULTICASTFRAME_G);
|
||||
mmc->mmc_tx_64_octets_gb += readl(ioaddr + MMC_TX_64_OCTETS_GB);
|
||||
mmc->mmc_tx_65_to_127_octets_gb +=
|
||||
readl(ioaddr + MMC_TX_65_TO_127_OCTETS_GB);
|
||||
mmc->mmc_tx_128_to_255_octets_gb +=
|
||||
readl(ioaddr + MMC_TX_128_TO_255_OCTETS_GB);
|
||||
mmc->mmc_tx_256_to_511_octets_gb +=
|
||||
readl(ioaddr + MMC_TX_256_TO_511_OCTETS_GB);
|
||||
mmc->mmc_tx_512_to_1023_octets_gb +=
|
||||
readl(ioaddr + MMC_TX_512_TO_1023_OCTETS_GB);
|
||||
mmc->mmc_tx_1024_to_max_octets_gb +=
|
||||
readl(ioaddr + MMC_TX_1024_TO_MAX_OCTETS_GB);
|
||||
mmc->mmc_tx_unicast_gb += readl(ioaddr + MMC_TX_UNICAST_GB);
|
||||
mmc->mmc_tx_multicast_gb += readl(ioaddr + MMC_TX_MULTICAST_GB);
|
||||
mmc->mmc_tx_broadcast_gb += readl(ioaddr + MMC_TX_BROADCAST_GB);
|
||||
mmc->mmc_tx_underflow_error += readl(ioaddr + MMC_TX_UNDERFLOW_ERROR);
|
||||
mmc->mmc_tx_singlecol_g += readl(ioaddr + MMC_TX_SINGLECOL_G);
|
||||
mmc->mmc_tx_multicol_g += readl(ioaddr + MMC_TX_MULTICOL_G);
|
||||
mmc->mmc_tx_deferred += readl(ioaddr + MMC_TX_DEFERRED);
|
||||
mmc->mmc_tx_latecol += readl(ioaddr + MMC_TX_LATECOL);
|
||||
mmc->mmc_tx_exesscol += readl(ioaddr + MMC_TX_EXESSCOL);
|
||||
mmc->mmc_tx_carrier_error += readl(ioaddr + MMC_TX_CARRIER_ERROR);
|
||||
mmc->mmc_tx_octetcount_g += readl(ioaddr + MMC_TX_OCTETCOUNT_G);
|
||||
mmc->mmc_tx_framecount_g += readl(ioaddr + MMC_TX_FRAMECOUNT_G);
|
||||
mmc->mmc_tx_excessdef += readl(ioaddr + MMC_TX_EXCESSDEF);
|
||||
mmc->mmc_tx_pause_frame += readl(ioaddr + MMC_TX_PAUSE_FRAME);
|
||||
mmc->mmc_tx_vlan_frame_g += readl(ioaddr + MMC_TX_VLAN_FRAME_G);
|
||||
|
||||
/* MMC RX counter registers */
|
||||
mmc->mmc_rx_framecount_gb += readl(ioaddr + MMC_RX_FRAMECOUNT_GB);
|
||||
mmc->mmc_rx_octetcount_gb += readl(ioaddr + MMC_RX_OCTETCOUNT_GB);
|
||||
mmc->mmc_rx_octetcount_g += readl(ioaddr + MMC_RX_OCTETCOUNT_G);
|
||||
mmc->mmc_rx_broadcastframe_g += readl(ioaddr + MMC_RX_BROADCASTFRAME_G);
|
||||
mmc->mmc_rx_multicastframe_g += readl(ioaddr + MMC_RX_MULTICASTFRAME_G);
|
||||
mmc->mmc_rx_crc_errror += readl(ioaddr + MMC_RX_CRC_ERRROR);
|
||||
mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR);
|
||||
mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR);
|
||||
mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR);
|
||||
mmc->mmc_rx_undersize_g += readl(ioaddr + MMC_RX_UNDERSIZE_G);
|
||||
mmc->mmc_rx_oversize_g += readl(ioaddr + MMC_RX_OVERSIZE_G);
|
||||
mmc->mmc_rx_64_octets_gb += readl(ioaddr + MMC_RX_64_OCTETS_GB);
|
||||
mmc->mmc_rx_65_to_127_octets_gb +=
|
||||
readl(ioaddr + MMC_RX_65_TO_127_OCTETS_GB);
|
||||
mmc->mmc_rx_128_to_255_octets_gb +=
|
||||
readl(ioaddr + MMC_RX_128_TO_255_OCTETS_GB);
|
||||
mmc->mmc_rx_256_to_511_octets_gb +=
|
||||
readl(ioaddr + MMC_RX_256_TO_511_OCTETS_GB);
|
||||
mmc->mmc_rx_512_to_1023_octets_gb +=
|
||||
readl(ioaddr + MMC_RX_512_TO_1023_OCTETS_GB);
|
||||
mmc->mmc_rx_1024_to_max_octets_gb +=
|
||||
readl(ioaddr + MMC_RX_1024_TO_MAX_OCTETS_GB);
|
||||
mmc->mmc_rx_unicast_g += readl(ioaddr + MMC_RX_UNICAST_G);
|
||||
mmc->mmc_rx_length_error += readl(ioaddr + MMC_RX_LENGTH_ERROR);
|
||||
mmc->mmc_rx_autofrangetype += readl(ioaddr + MMC_RX_AUTOFRANGETYPE);
|
||||
mmc->mmc_rx_pause_frames += readl(ioaddr + MMC_RX_PAUSE_FRAMES);
|
||||
mmc->mmc_rx_fifo_overflow += readl(ioaddr + MMC_RX_FIFO_OVERFLOW);
|
||||
mmc->mmc_rx_vlan_frames_gb += readl(ioaddr + MMC_RX_VLAN_FRAMES_GB);
|
||||
mmc->mmc_rx_watchdog_error += readl(ioaddr + MMC_RX_WATCHDOG_ERROR);
|
||||
/* IPC */
|
||||
mmc->mmc_rx_ipc_intr_mask += readl(ioaddr + MMC_RX_IPC_INTR_MASK);
|
||||
mmc->mmc_rx_ipc_intr += readl(ioaddr + MMC_RX_IPC_INTR);
|
||||
/* IPv4 */
|
||||
mmc->mmc_rx_ipv4_gd += readl(ioaddr + MMC_RX_IPV4_GD);
|
||||
mmc->mmc_rx_ipv4_hderr += readl(ioaddr + MMC_RX_IPV4_HDERR);
|
||||
mmc->mmc_rx_ipv4_nopay += readl(ioaddr + MMC_RX_IPV4_NOPAY);
|
||||
mmc->mmc_rx_ipv4_frag += readl(ioaddr + MMC_RX_IPV4_FRAG);
|
||||
mmc->mmc_rx_ipv4_udsbl += readl(ioaddr + MMC_RX_IPV4_UDSBL);
|
||||
|
||||
mmc->mmc_rx_ipv4_gd_octets += readl(ioaddr + MMC_RX_IPV4_GD_OCTETS);
|
||||
mmc->mmc_rx_ipv4_hderr_octets +=
|
||||
readl(ioaddr + MMC_RX_IPV4_HDERR_OCTETS);
|
||||
mmc->mmc_rx_ipv4_nopay_octets +=
|
||||
readl(ioaddr + MMC_RX_IPV4_NOPAY_OCTETS);
|
||||
mmc->mmc_rx_ipv4_frag_octets += readl(ioaddr + MMC_RX_IPV4_FRAG_OCTETS);
|
||||
mmc->mmc_rx_ipv4_udsbl_octets +=
|
||||
readl(ioaddr + MMC_RX_IPV4_UDSBL_OCTETS);
|
||||
|
||||
/* IPV6 */
|
||||
mmc->mmc_rx_ipv6_gd_octets += readl(ioaddr + MMC_RX_IPV6_GD_OCTETS);
|
||||
mmc->mmc_rx_ipv6_hderr_octets +=
|
||||
readl(ioaddr + MMC_RX_IPV6_HDERR_OCTETS);
|
||||
mmc->mmc_rx_ipv6_nopay_octets +=
|
||||
readl(ioaddr + MMC_RX_IPV6_NOPAY_OCTETS);
|
||||
|
||||
mmc->mmc_rx_ipv6_gd += readl(ioaddr + MMC_RX_IPV6_GD);
|
||||
mmc->mmc_rx_ipv6_hderr += readl(ioaddr + MMC_RX_IPV6_HDERR);
|
||||
mmc->mmc_rx_ipv6_nopay += readl(ioaddr + MMC_RX_IPV6_NOPAY);
|
||||
|
||||
/* Protocols */
|
||||
mmc->mmc_rx_udp_gd += readl(ioaddr + MMC_RX_UDP_GD);
|
||||
mmc->mmc_rx_udp_err += readl(ioaddr + MMC_RX_UDP_ERR);
|
||||
mmc->mmc_rx_tcp_gd += readl(ioaddr + MMC_RX_TCP_GD);
|
||||
mmc->mmc_rx_tcp_err += readl(ioaddr + MMC_RX_TCP_ERR);
|
||||
mmc->mmc_rx_icmp_gd += readl(ioaddr + MMC_RX_ICMP_GD);
|
||||
mmc->mmc_rx_icmp_err += readl(ioaddr + MMC_RX_ICMP_ERR);
|
||||
|
||||
mmc->mmc_rx_udp_gd_octets += readl(ioaddr + MMC_RX_UDP_GD_OCTETS);
|
||||
mmc->mmc_rx_udp_err_octets += readl(ioaddr + MMC_RX_UDP_ERR_OCTETS);
|
||||
mmc->mmc_rx_tcp_gd_octets += readl(ioaddr + MMC_RX_TCP_GD_OCTETS);
|
||||
mmc->mmc_rx_tcp_err_octets += readl(ioaddr + MMC_RX_TCP_ERR_OCTETS);
|
||||
mmc->mmc_rx_icmp_gd_octets += readl(ioaddr + MMC_RX_ICMP_GD_OCTETS);
|
||||
mmc->mmc_rx_icmp_err_octets += readl(ioaddr + MMC_RX_ICMP_ERR_OCTETS);
|
||||
}
|
||||
275
drivers/net/ethernet/rockchip/gmac/norm_desc.c
Executable file
275
drivers/net/ethernet/rockchip/gmac/norm_desc.c
Executable file
@@ -0,0 +1,275 @@
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the normal descriptors.
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/stmmac.h>
|
||||
#include "common.h"
|
||||
#include "descs_com.h"
|
||||
|
||||
static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p, void __iomem *ioaddr)
|
||||
{
|
||||
int ret = 0;
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
|
||||
if (unlikely(p->des01.tx.error_summary)) {
|
||||
if (unlikely(p->des01.tx.underflow_error)) {
|
||||
x->tx_underflow++;
|
||||
stats->tx_fifo_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.tx.no_carrier)) {
|
||||
x->tx_carrier++;
|
||||
stats->tx_carrier_errors++;
|
||||
}
|
||||
if (unlikely(p->des01.tx.loss_carrier)) {
|
||||
x->tx_losscarrier++;
|
||||
stats->tx_carrier_errors++;
|
||||
}
|
||||
if (unlikely((p->des01.tx.excessive_deferral) ||
|
||||
(p->des01.tx.excessive_collisions) ||
|
||||
(p->des01.tx.late_collision)))
|
||||
stats->collisions += p->des01.tx.collision_count;
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (p->des01.etx.vlan_frame) {
|
||||
CHIP_DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
|
||||
x->tx_vlan++;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.tx.deferred))
|
||||
x->tx_deferred++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_len(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.tx.buffer1_size;
|
||||
}
|
||||
|
||||
/* This function verifies if each incoming frame has some errors
|
||||
* and, if required, updates the multicast statistics.
|
||||
* In case of success, it returns good_frame because the GMAC device
|
||||
* is supposed to be able to compute the csum in HW. */
|
||||
static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
|
||||
struct dma_desc *p)
|
||||
{
|
||||
int ret = good_frame;
|
||||
struct net_device_stats *stats = (struct net_device_stats *)data;
|
||||
|
||||
if (unlikely(p->des01.rx.last_descriptor == 0)) {
|
||||
pr_warn("%s: Oversized frame spanned multiple buffers\n",
|
||||
__func__);
|
||||
stats->rx_length_errors++;
|
||||
return discard_frame;
|
||||
}
|
||||
|
||||
if (unlikely(p->des01.rx.error_summary)) {
|
||||
if (unlikely(p->des01.rx.descriptor_error))
|
||||
x->rx_desc++;
|
||||
if (unlikely(p->des01.rx.sa_filter_fail))
|
||||
x->sa_filter_fail++;
|
||||
if (unlikely(p->des01.rx.overflow_error))
|
||||
x->overflow_error++;
|
||||
if (unlikely(p->des01.rx.ipc_csum_error))
|
||||
x->ipc_csum_error++;
|
||||
if (unlikely(p->des01.rx.collision)) {
|
||||
x->rx_collision++;
|
||||
stats->collisions++;
|
||||
}
|
||||
if (unlikely(p->des01.rx.crc_error)) {
|
||||
x->rx_crc++;
|
||||
stats->rx_crc_errors++;
|
||||
}
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(p->des01.rx.dribbling))
|
||||
x->dribbling_bit++;
|
||||
|
||||
if (unlikely(p->des01.rx.length_error)) {
|
||||
x->rx_length++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
if (unlikely(p->des01.rx.mii_error)) {
|
||||
x->rx_mii++;
|
||||
ret = discard_frame;
|
||||
}
|
||||
#ifdef STMMAC_VLAN_TAG_USED
|
||||
if (p->des01.rx.vlan_tag)
|
||||
x->vlan_tag++;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
|
||||
int end)
|
||||
{
|
||||
p->des01.rx.own = 1;
|
||||
p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
|
||||
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_rx_set_on_chain(p, end);
|
||||
else
|
||||
ndesc_rx_set_on_ring(p, end);
|
||||
|
||||
if (disable_rx_ic)
|
||||
p->des01.rx.disable_ic = 1;
|
||||
}
|
||||
|
||||
static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
|
||||
{
|
||||
p->des01.tx.own = 0;
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_tx_set_on_chain(p, end);
|
||||
else
|
||||
ndesc_tx_set_on_ring(p, end);
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.tx.own;
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_owner(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.rx.own;
|
||||
}
|
||||
|
||||
static void ndesc_set_tx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des01.tx.own = 1;
|
||||
}
|
||||
|
||||
static void ndesc_set_rx_owner(struct dma_desc *p)
|
||||
{
|
||||
p->des01.rx.own = 1;
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_ls(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.tx.last_segment;
|
||||
}
|
||||
|
||||
static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
|
||||
{
|
||||
int ter = p->des01.tx.end_ring;
|
||||
|
||||
memset(p, 0, offsetof(struct dma_desc, des2));
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
ndesc_end_tx_desc_on_chain(p, ter);
|
||||
else
|
||||
ndesc_end_tx_desc_on_ring(p, ter);
|
||||
}
|
||||
|
||||
static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
|
||||
int csum_flag, int mode)
|
||||
{
|
||||
p->des01.tx.first_segment = is_fs;
|
||||
if (mode == STMMAC_CHAIN_MODE)
|
||||
norm_set_tx_desc_len_on_chain(p, len);
|
||||
else
|
||||
norm_set_tx_desc_len_on_ring(p, len);
|
||||
|
||||
if (likely(csum_flag))
|
||||
p->des01.tx.checksum_insertion = cic_full;
|
||||
}
|
||||
|
||||
static void ndesc_clear_tx_ic(struct dma_desc *p)
|
||||
{
|
||||
p->des01.tx.interrupt = 0;
|
||||
}
|
||||
|
||||
static void ndesc_close_tx_desc(struct dma_desc *p)
|
||||
{
|
||||
p->des01.tx.last_segment = 1;
|
||||
p->des01.tx.interrupt = 1;
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
|
||||
{
|
||||
/* The type-1 checksum offload engines append the checksum at
|
||||
* the end of frame and the two bytes of checksum are added in
|
||||
* the length.
|
||||
* Adjust for that in the framelen for type-1 checksum offload
|
||||
* engines. */
|
||||
if (rx_coe_type == STMMAC_RX_COE_TYPE1)
|
||||
return p->des01.rx.frame_length - 2;
|
||||
else
|
||||
return p->des01.rx.frame_length;
|
||||
}
|
||||
|
||||
static void ndesc_enable_tx_timestamp(struct dma_desc *p)
|
||||
{
|
||||
p->des01.tx.time_stamp_enable = 1;
|
||||
}
|
||||
|
||||
static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
|
||||
{
|
||||
return p->des01.tx.time_stamp_status;
|
||||
}
|
||||
|
||||
static u64 ndesc_get_timestamp(void *desc, u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
u64 ns;
|
||||
|
||||
ns = p->des2;
|
||||
/* convert high/sec time stamp value to nanosecond */
|
||||
ns += p->des3 * 1000000000ULL;
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
static int ndesc_get_rx_timestamp_status(void *desc, u32 ats)
|
||||
{
|
||||
struct dma_desc *p = (struct dma_desc *)desc;
|
||||
|
||||
if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
|
||||
/* timestamp is corrupted, hence don't store it */
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
const struct stmmac_desc_ops ndesc_ops = {
|
||||
.tx_status = ndesc_get_tx_status,
|
||||
.rx_status = ndesc_get_rx_status,
|
||||
.get_tx_len = ndesc_get_tx_len,
|
||||
.init_rx_desc = ndesc_init_rx_desc,
|
||||
.init_tx_desc = ndesc_init_tx_desc,
|
||||
.get_tx_owner = ndesc_get_tx_owner,
|
||||
.get_rx_owner = ndesc_get_rx_owner,
|
||||
.release_tx_desc = ndesc_release_tx_desc,
|
||||
.prepare_tx_desc = ndesc_prepare_tx_desc,
|
||||
.clear_tx_ic = ndesc_clear_tx_ic,
|
||||
.close_tx_desc = ndesc_close_tx_desc,
|
||||
.get_tx_ls = ndesc_get_tx_ls,
|
||||
.set_tx_owner = ndesc_set_tx_owner,
|
||||
.set_rx_owner = ndesc_set_rx_owner,
|
||||
.get_rx_frame_len = ndesc_get_rx_frame_len,
|
||||
.enable_tx_timestamp = ndesc_enable_tx_timestamp,
|
||||
.get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
|
||||
.get_timestamp = ndesc_get_timestamp,
|
||||
.get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
|
||||
};
|
||||
127
drivers/net/ethernet/rockchip/gmac/ring_mode.c
Executable file
127
drivers/net/ethernet/rockchip/gmac/ring_mode.c
Executable file
@@ -0,0 +1,127 @@
|
||||
/*******************************************************************************
|
||||
Specialised functions for managing Ring mode
|
||||
|
||||
Copyright(C) 2011 STMicroelectronics Ltd
|
||||
|
||||
It defines all the functions used to handle the normal/enhanced
|
||||
descriptors in case of the DMA is configured to work in chained or
|
||||
in ring mode.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include "stmmac.h"
|
||||
|
||||
static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)p;
|
||||
unsigned int txsize = priv->dma_tx_size;
|
||||
unsigned int entry = priv->cur_tx % txsize;
|
||||
struct dma_desc *desc = priv->dma_tx + entry;
|
||||
unsigned int nopaged_len = skb_headlen(skb);
|
||||
unsigned int bmax, len;
|
||||
|
||||
if (priv->plat->enh_desc)
|
||||
bmax = BUF_SIZE_8KiB;
|
||||
else
|
||||
bmax = BUF_SIZE_2KiB;
|
||||
|
||||
len = nopaged_len - bmax;
|
||||
|
||||
if (nopaged_len > BUF_SIZE_8KiB) {
|
||||
|
||||
desc->des2 = dma_map_single(priv->device, skb->data,
|
||||
bmax, DMA_TO_DEVICE);
|
||||
priv->tx_skbuff_dma[entry] = desc->des2;
|
||||
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
|
||||
STMMAC_RING_MODE);
|
||||
wmb();
|
||||
entry = (++priv->cur_tx) % txsize;
|
||||
desc = priv->dma_tx + entry;
|
||||
|
||||
desc->des2 = dma_map_single(priv->device, skb->data + bmax,
|
||||
len, DMA_TO_DEVICE);
|
||||
priv->tx_skbuff_dma[entry] = desc->des2;
|
||||
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
|
||||
STMMAC_RING_MODE);
|
||||
wmb();
|
||||
priv->hw->desc->set_tx_owner(desc);
|
||||
priv->tx_skbuff[entry] = NULL;
|
||||
} else {
|
||||
desc->des2 = dma_map_single(priv->device, skb->data,
|
||||
nopaged_len, DMA_TO_DEVICE);
|
||||
priv->tx_skbuff_dma[entry] = desc->des2;
|
||||
desc->des3 = desc->des2 + BUF_SIZE_4KiB;
|
||||
priv->hw->desc->prepare_tx_desc(desc, 1, nopaged_len, csum,
|
||||
STMMAC_RING_MODE);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static unsigned int stmmac_is_jumbo_frm(int len, int enh_desc)
|
||||
{
|
||||
unsigned int ret = 0;
|
||||
|
||||
if (len >= BUF_SIZE_4KiB)
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stmmac_refill_desc3(void *priv_ptr, struct dma_desc *p)
|
||||
{
|
||||
struct stmmac_priv *priv = (struct stmmac_priv *)priv_ptr;
|
||||
|
||||
if (unlikely(priv->plat->has_gmac))
|
||||
/* Fill DES3 in case of RING mode */
|
||||
if (priv->dma_buf_sz >= BUF_SIZE_8KiB)
|
||||
p->des3 = p->des2 + BUF_SIZE_8KiB;
|
||||
}
|
||||
|
||||
/* In ring mode we need to fill the desc3 because it is used as buffer */
|
||||
static void stmmac_init_desc3(struct dma_desc *p)
|
||||
{
|
||||
p->des3 = p->des2 + BUF_SIZE_8KiB;
|
||||
}
|
||||
|
||||
static void stmmac_clean_desc3(void *priv_ptr, struct dma_desc *p)
|
||||
{
|
||||
if (unlikely(p->des3))
|
||||
p->des3 = 0;
|
||||
}
|
||||
|
||||
static int stmmac_set_16kib_bfsize(int mtu)
|
||||
{
|
||||
int ret = 0;
|
||||
if (unlikely(mtu >= BUF_SIZE_8KiB))
|
||||
ret = BUF_SIZE_16KiB;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct stmmac_ring_mode_ops ring_mode_ops = {
|
||||
.is_jumbo_frm = stmmac_is_jumbo_frm,
|
||||
.jumbo_frm = stmmac_jumbo_frm,
|
||||
.refill_desc3 = stmmac_refill_desc3,
|
||||
.init_desc3 = stmmac_init_desc3,
|
||||
.clean_desc3 = stmmac_clean_desc3,
|
||||
.set_16kib_bfsize = stmmac_set_16kib_bfsize,
|
||||
};
|
||||
180
drivers/net/ethernet/rockchip/gmac/stmmac.h
Executable file
180
drivers/net/ethernet/rockchip/gmac/stmmac.h
Executable file
@@ -0,0 +1,180 @@
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef __STMMAC_H__
|
||||
#define __STMMAC_H__
|
||||
|
||||
#define STMMAC_RESOURCE_NAME "stmmaceth"
|
||||
#define DRV_MODULE_VERSION "March_2013"
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/stmmac.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/pci.h>
|
||||
#include "common.h"
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
|
||||
struct stmmac_priv {
|
||||
/* Frequently used values are kept adjacent for cache effect */
|
||||
struct dma_extended_desc *dma_etx ____cacheline_aligned_in_smp;
|
||||
struct dma_desc *dma_tx;
|
||||
struct sk_buff **tx_skbuff;
|
||||
unsigned int cur_tx;
|
||||
unsigned int dirty_tx;
|
||||
unsigned int dma_tx_size;
|
||||
u32 tx_count_frames;
|
||||
u32 tx_coal_frames;
|
||||
u32 tx_coal_timer;
|
||||
dma_addr_t *tx_skbuff_dma;
|
||||
dma_addr_t dma_tx_phy;
|
||||
int tx_coalesce;
|
||||
int hwts_tx_en;
|
||||
spinlock_t tx_lock;
|
||||
bool tx_path_in_lpi_mode;
|
||||
struct timer_list txtimer;
|
||||
|
||||
struct dma_desc *dma_rx ____cacheline_aligned_in_smp;
|
||||
struct dma_extended_desc *dma_erx;
|
||||
struct sk_buff **rx_skbuff;
|
||||
unsigned int cur_rx;
|
||||
unsigned int dirty_rx;
|
||||
unsigned int dma_rx_size;
|
||||
unsigned int dma_buf_sz;
|
||||
u32 rx_riwt;
|
||||
int hwts_rx_en;
|
||||
dma_addr_t *rx_skbuff_dma;
|
||||
dma_addr_t dma_rx_phy;
|
||||
|
||||
struct napi_struct napi ____cacheline_aligned_in_smp;
|
||||
|
||||
void __iomem *ioaddr;
|
||||
struct net_device *dev;
|
||||
struct device *device;
|
||||
struct mac_device_info *hw;
|
||||
int no_csum_insertion;
|
||||
spinlock_t lock;
|
||||
|
||||
struct phy_device *phydev ____cacheline_aligned_in_smp;
|
||||
int oldlink;
|
||||
int speed;
|
||||
int oldduplex;
|
||||
unsigned int flow_ctrl;
|
||||
unsigned int pause;
|
||||
struct mii_bus *mii;
|
||||
int mii_irq[PHY_MAX_ADDR];
|
||||
|
||||
struct stmmac_extra_stats xstats ____cacheline_aligned_in_smp;
|
||||
struct plat_stmmacenet_data *plat;
|
||||
struct dma_features dma_cap;
|
||||
struct stmmac_counters mmc;
|
||||
int hw_cap_support;
|
||||
int synopsys_id;
|
||||
u32 msg_enable;
|
||||
int wolopts;
|
||||
int wol_irq;
|
||||
struct clk *stmmac_clk;
|
||||
int clk_csr;
|
||||
struct timer_list eee_ctrl_timer;
|
||||
int lpi_irq;
|
||||
int eee_enabled;
|
||||
int eee_active;
|
||||
int tx_lpi_timer;
|
||||
int pcs;
|
||||
unsigned int mode;
|
||||
int extend_desc;
|
||||
struct ptp_clock *ptp_clock;
|
||||
struct ptp_clock_info ptp_clock_ops;
|
||||
unsigned int default_addend;
|
||||
u32 adv_ts;
|
||||
int use_riwt;
|
||||
spinlock_t ptp_lock;
|
||||
};
|
||||
|
||||
extern int phyaddr;
|
||||
|
||||
extern int stmmac_mdio_unregister(struct net_device *ndev);
|
||||
extern int stmmac_mdio_register(struct net_device *ndev);
|
||||
extern void stmmac_set_ethtool_ops(struct net_device *netdev);
|
||||
extern const struct stmmac_desc_ops enh_desc_ops;
|
||||
extern const struct stmmac_desc_ops ndesc_ops;
|
||||
extern const struct stmmac_hwtimestamp stmmac_ptp;
|
||||
extern int stmmac_ptp_register(struct stmmac_priv *priv);
|
||||
extern void stmmac_ptp_unregister(struct stmmac_priv *priv);
|
||||
int stmmac_freeze(struct net_device *ndev);
|
||||
int stmmac_restore(struct net_device *ndev);
|
||||
int stmmac_resume(struct net_device *ndev);
|
||||
int stmmac_suspend(struct net_device *ndev);
|
||||
int stmmac_dvr_remove(struct net_device *ndev);
|
||||
struct stmmac_priv *stmmac_dvr_probe(struct device *device,
|
||||
struct plat_stmmacenet_data *plat_dat,
|
||||
void __iomem *addr);
|
||||
void stmmac_disable_eee_mode(struct stmmac_priv *priv);
|
||||
bool stmmac_eee_init(struct stmmac_priv *priv);
|
||||
|
||||
extern struct platform_driver stmmac_pltfr_driver;
|
||||
static inline int stmmac_register_platform(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = platform_driver_register(&stmmac_pltfr_driver);
|
||||
if (err)
|
||||
pr_err("stmmac: failed to register the platform driver\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void stmmac_unregister_platform(void)
|
||||
{
|
||||
platform_driver_unregister(&stmmac_pltfr_driver);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STMMAC_PCI
|
||||
extern struct pci_driver stmmac_pci_driver;
|
||||
static inline int stmmac_register_pci(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pci_register_driver(&stmmac_pci_driver);
|
||||
if (err)
|
||||
pr_err("stmmac: failed to register the PCI driver\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void stmmac_unregister_pci(void)
|
||||
{
|
||||
pci_unregister_driver(&stmmac_pci_driver);
|
||||
}
|
||||
#else
|
||||
static inline int stmmac_register_pci(void)
|
||||
{
|
||||
pr_debug("stmmac: do not register the PCI driver\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void stmmac_unregister_pci(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_STMMAC_PCI */
|
||||
|
||||
#endif /* __STMMAC_H__ */
|
||||
788
drivers/net/ethernet/rockchip/gmac/stmmac_ethtool.c
Executable file
788
drivers/net/ethernet/rockchip/gmac/stmmac_ethtool.c
Executable file
@@ -0,0 +1,788 @@
|
||||
/*******************************************************************************
|
||||
STMMAC Ethtool support
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "stmmac.h"
|
||||
#include "dwmac_dma.h"
|
||||
|
||||
#define REG_SPACE_SIZE 0x1054
|
||||
#define MAC100_ETHTOOL_NAME "st_mac100"
|
||||
#define GMAC_ETHTOOL_NAME "st_gmac"
|
||||
|
||||
struct stmmac_stats {
|
||||
char stat_string[ETH_GSTRING_LEN];
|
||||
int sizeof_stat;
|
||||
int stat_offset;
|
||||
};
|
||||
|
||||
#define STMMAC_STAT(m) \
|
||||
{ #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \
|
||||
offsetof(struct stmmac_priv, xstats.m)}
|
||||
|
||||
static const struct stmmac_stats stmmac_gstrings_stats[] = {
|
||||
/* Transmit errors */
|
||||
STMMAC_STAT(tx_underflow),
|
||||
STMMAC_STAT(tx_carrier),
|
||||
STMMAC_STAT(tx_losscarrier),
|
||||
STMMAC_STAT(vlan_tag),
|
||||
STMMAC_STAT(tx_deferred),
|
||||
STMMAC_STAT(tx_vlan),
|
||||
STMMAC_STAT(tx_jabber),
|
||||
STMMAC_STAT(tx_frame_flushed),
|
||||
STMMAC_STAT(tx_payload_error),
|
||||
STMMAC_STAT(tx_ip_header_error),
|
||||
/* Receive errors */
|
||||
STMMAC_STAT(rx_desc),
|
||||
STMMAC_STAT(sa_filter_fail),
|
||||
STMMAC_STAT(overflow_error),
|
||||
STMMAC_STAT(ipc_csum_error),
|
||||
STMMAC_STAT(rx_collision),
|
||||
STMMAC_STAT(rx_crc),
|
||||
STMMAC_STAT(dribbling_bit),
|
||||
STMMAC_STAT(rx_length),
|
||||
STMMAC_STAT(rx_mii),
|
||||
STMMAC_STAT(rx_multicast),
|
||||
STMMAC_STAT(rx_gmac_overflow),
|
||||
STMMAC_STAT(rx_watchdog),
|
||||
STMMAC_STAT(da_rx_filter_fail),
|
||||
STMMAC_STAT(sa_rx_filter_fail),
|
||||
STMMAC_STAT(rx_missed_cntr),
|
||||
STMMAC_STAT(rx_overflow_cntr),
|
||||
STMMAC_STAT(rx_vlan),
|
||||
/* Tx/Rx IRQ error info */
|
||||
STMMAC_STAT(tx_undeflow_irq),
|
||||
STMMAC_STAT(tx_process_stopped_irq),
|
||||
STMMAC_STAT(tx_jabber_irq),
|
||||
STMMAC_STAT(rx_overflow_irq),
|
||||
STMMAC_STAT(rx_buf_unav_irq),
|
||||
STMMAC_STAT(rx_process_stopped_irq),
|
||||
STMMAC_STAT(rx_watchdog_irq),
|
||||
STMMAC_STAT(tx_early_irq),
|
||||
STMMAC_STAT(fatal_bus_error_irq),
|
||||
/* Tx/Rx IRQ Events */
|
||||
STMMAC_STAT(rx_early_irq),
|
||||
STMMAC_STAT(threshold),
|
||||
STMMAC_STAT(tx_pkt_n),
|
||||
STMMAC_STAT(rx_pkt_n),
|
||||
STMMAC_STAT(normal_irq_n),
|
||||
STMMAC_STAT(rx_normal_irq_n),
|
||||
STMMAC_STAT(napi_poll),
|
||||
STMMAC_STAT(tx_normal_irq_n),
|
||||
STMMAC_STAT(tx_clean),
|
||||
STMMAC_STAT(tx_reset_ic_bit),
|
||||
STMMAC_STAT(irq_receive_pmt_irq_n),
|
||||
/* MMC info */
|
||||
STMMAC_STAT(mmc_tx_irq_n),
|
||||
STMMAC_STAT(mmc_rx_irq_n),
|
||||
STMMAC_STAT(mmc_rx_csum_offload_irq_n),
|
||||
/* EEE */
|
||||
STMMAC_STAT(irq_tx_path_in_lpi_mode_n),
|
||||
STMMAC_STAT(irq_tx_path_exit_lpi_mode_n),
|
||||
STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
|
||||
STMMAC_STAT(irq_rx_path_exit_lpi_mode_n),
|
||||
STMMAC_STAT(phy_eee_wakeup_error_n),
|
||||
/* Extended RDES status */
|
||||
STMMAC_STAT(ip_hdr_err),
|
||||
STMMAC_STAT(ip_payload_err),
|
||||
STMMAC_STAT(ip_csum_bypassed),
|
||||
STMMAC_STAT(ipv4_pkt_rcvd),
|
||||
STMMAC_STAT(ipv6_pkt_rcvd),
|
||||
STMMAC_STAT(rx_msg_type_ext_no_ptp),
|
||||
STMMAC_STAT(rx_msg_type_sync),
|
||||
STMMAC_STAT(rx_msg_type_follow_up),
|
||||
STMMAC_STAT(rx_msg_type_delay_req),
|
||||
STMMAC_STAT(rx_msg_type_delay_resp),
|
||||
STMMAC_STAT(rx_msg_type_pdelay_req),
|
||||
STMMAC_STAT(rx_msg_type_pdelay_resp),
|
||||
STMMAC_STAT(rx_msg_type_pdelay_follow_up),
|
||||
STMMAC_STAT(ptp_frame_type),
|
||||
STMMAC_STAT(ptp_ver),
|
||||
STMMAC_STAT(timestamp_dropped),
|
||||
STMMAC_STAT(av_pkt_rcvd),
|
||||
STMMAC_STAT(av_tagged_pkt_rcvd),
|
||||
STMMAC_STAT(vlan_tag_priority_val),
|
||||
STMMAC_STAT(l3_filter_match),
|
||||
STMMAC_STAT(l4_filter_match),
|
||||
STMMAC_STAT(l3_l4_filter_no_match),
|
||||
/* PCS */
|
||||
STMMAC_STAT(irq_pcs_ane_n),
|
||||
STMMAC_STAT(irq_pcs_link_n),
|
||||
STMMAC_STAT(irq_rgmii_n),
|
||||
};
|
||||
#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
|
||||
|
||||
/* HW MAC Management counters (if supported) */
|
||||
#define STMMAC_MMC_STAT(m) \
|
||||
{ #m, FIELD_SIZEOF(struct stmmac_counters, m), \
|
||||
offsetof(struct stmmac_priv, mmc.m)}
|
||||
|
||||
static const struct stmmac_stats stmmac_mmc[] = {
|
||||
STMMAC_MMC_STAT(mmc_tx_octetcount_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_framecount_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_broadcastframe_g),
|
||||
STMMAC_MMC_STAT(mmc_tx_multicastframe_g),
|
||||
STMMAC_MMC_STAT(mmc_tx_64_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_65_to_127_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_128_to_255_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_256_to_511_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_512_to_1023_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_1024_to_max_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_unicast_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_multicast_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_broadcast_gb),
|
||||
STMMAC_MMC_STAT(mmc_tx_underflow_error),
|
||||
STMMAC_MMC_STAT(mmc_tx_singlecol_g),
|
||||
STMMAC_MMC_STAT(mmc_tx_multicol_g),
|
||||
STMMAC_MMC_STAT(mmc_tx_deferred),
|
||||
STMMAC_MMC_STAT(mmc_tx_latecol),
|
||||
STMMAC_MMC_STAT(mmc_tx_exesscol),
|
||||
STMMAC_MMC_STAT(mmc_tx_carrier_error),
|
||||
STMMAC_MMC_STAT(mmc_tx_octetcount_g),
|
||||
STMMAC_MMC_STAT(mmc_tx_framecount_g),
|
||||
STMMAC_MMC_STAT(mmc_tx_excessdef),
|
||||
STMMAC_MMC_STAT(mmc_tx_pause_frame),
|
||||
STMMAC_MMC_STAT(mmc_tx_vlan_frame_g),
|
||||
STMMAC_MMC_STAT(mmc_rx_framecount_gb),
|
||||
STMMAC_MMC_STAT(mmc_rx_octetcount_gb),
|
||||
STMMAC_MMC_STAT(mmc_rx_octetcount_g),
|
||||
STMMAC_MMC_STAT(mmc_rx_broadcastframe_g),
|
||||
STMMAC_MMC_STAT(mmc_rx_multicastframe_g),
|
||||
STMMAC_MMC_STAT(mmc_rx_crc_errror),
|
||||
STMMAC_MMC_STAT(mmc_rx_align_error),
|
||||
STMMAC_MMC_STAT(mmc_rx_run_error),
|
||||
STMMAC_MMC_STAT(mmc_rx_jabber_error),
|
||||
STMMAC_MMC_STAT(mmc_rx_undersize_g),
|
||||
STMMAC_MMC_STAT(mmc_rx_oversize_g),
|
||||
STMMAC_MMC_STAT(mmc_rx_64_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_rx_65_to_127_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_rx_128_to_255_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_rx_256_to_511_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_rx_512_to_1023_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_rx_1024_to_max_octets_gb),
|
||||
STMMAC_MMC_STAT(mmc_rx_unicast_g),
|
||||
STMMAC_MMC_STAT(mmc_rx_length_error),
|
||||
STMMAC_MMC_STAT(mmc_rx_autofrangetype),
|
||||
STMMAC_MMC_STAT(mmc_rx_pause_frames),
|
||||
STMMAC_MMC_STAT(mmc_rx_fifo_overflow),
|
||||
STMMAC_MMC_STAT(mmc_rx_vlan_frames_gb),
|
||||
STMMAC_MMC_STAT(mmc_rx_watchdog_error),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipc_intr_mask),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipc_intr),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_gd),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_hderr),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_nopay),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_frag),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_gd_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_hderr_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_nopay_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_frag_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv4_udsbl_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv6_gd_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv6_hderr_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv6_nopay_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv6_gd),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv6_hderr),
|
||||
STMMAC_MMC_STAT(mmc_rx_ipv6_nopay),
|
||||
STMMAC_MMC_STAT(mmc_rx_udp_gd),
|
||||
STMMAC_MMC_STAT(mmc_rx_udp_err),
|
||||
STMMAC_MMC_STAT(mmc_rx_tcp_gd),
|
||||
STMMAC_MMC_STAT(mmc_rx_tcp_err),
|
||||
STMMAC_MMC_STAT(mmc_rx_icmp_gd),
|
||||
STMMAC_MMC_STAT(mmc_rx_icmp_err),
|
||||
STMMAC_MMC_STAT(mmc_rx_udp_gd_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_udp_err_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_tcp_gd_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_tcp_err_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_icmp_gd_octets),
|
||||
STMMAC_MMC_STAT(mmc_rx_icmp_err_octets),
|
||||
};
|
||||
#define STMMAC_MMC_STATS_LEN ARRAY_SIZE(stmmac_mmc)
|
||||
|
||||
static void stmmac_ethtool_getdrvinfo(struct net_device *dev,
|
||||
struct ethtool_drvinfo *info)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (priv->plat->has_gmac)
|
||||
strlcpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver));
|
||||
else
|
||||
strlcpy(info->driver, MAC100_ETHTOOL_NAME,
|
||||
sizeof(info->driver));
|
||||
|
||||
strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_getsettings(struct net_device *dev,
|
||||
struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phy = priv->phydev;
|
||||
int rc;
|
||||
|
||||
if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) {
|
||||
struct rgmii_adv adv;
|
||||
|
||||
if (!priv->xstats.pcs_link) {
|
||||
ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
|
||||
cmd->duplex = DUPLEX_UNKNOWN;
|
||||
return 0;
|
||||
}
|
||||
cmd->duplex = priv->xstats.pcs_duplex;
|
||||
|
||||
ethtool_cmd_speed_set(cmd, priv->xstats.pcs_speed);
|
||||
|
||||
/* Get and convert ADV/LP_ADV from the HW AN registers */
|
||||
if (priv->hw->mac->get_adv)
|
||||
priv->hw->mac->get_adv(priv->ioaddr, &adv);
|
||||
else
|
||||
return -EOPNOTSUPP; /* should never happen indeed */
|
||||
|
||||
/* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */
|
||||
|
||||
if (adv.pause & STMMAC_PCS_PAUSE)
|
||||
cmd->advertising |= ADVERTISED_Pause;
|
||||
if (adv.pause & STMMAC_PCS_ASYM_PAUSE)
|
||||
cmd->advertising |= ADVERTISED_Asym_Pause;
|
||||
if (adv.lp_pause & STMMAC_PCS_PAUSE)
|
||||
cmd->lp_advertising |= ADVERTISED_Pause;
|
||||
if (adv.lp_pause & STMMAC_PCS_ASYM_PAUSE)
|
||||
cmd->lp_advertising |= ADVERTISED_Asym_Pause;
|
||||
|
||||
/* Reg49[3] always set because ANE is always supported */
|
||||
cmd->autoneg = ADVERTISED_Autoneg;
|
||||
cmd->supported |= SUPPORTED_Autoneg;
|
||||
cmd->advertising |= ADVERTISED_Autoneg;
|
||||
cmd->lp_advertising |= ADVERTISED_Autoneg;
|
||||
|
||||
if (adv.duplex) {
|
||||
cmd->supported |= (SUPPORTED_1000baseT_Full |
|
||||
SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_10baseT_Full);
|
||||
cmd->advertising |= (ADVERTISED_1000baseT_Full |
|
||||
ADVERTISED_100baseT_Full |
|
||||
ADVERTISED_10baseT_Full);
|
||||
} else {
|
||||
cmd->supported |= (SUPPORTED_1000baseT_Half |
|
||||
SUPPORTED_100baseT_Half |
|
||||
SUPPORTED_10baseT_Half);
|
||||
cmd->advertising |= (ADVERTISED_1000baseT_Half |
|
||||
ADVERTISED_100baseT_Half |
|
||||
ADVERTISED_10baseT_Half);
|
||||
}
|
||||
if (adv.lp_duplex)
|
||||
cmd->lp_advertising |= (ADVERTISED_1000baseT_Full |
|
||||
ADVERTISED_100baseT_Full |
|
||||
ADVERTISED_10baseT_Full);
|
||||
else
|
||||
cmd->lp_advertising |= (ADVERTISED_1000baseT_Half |
|
||||
ADVERTISED_100baseT_Half |
|
||||
ADVERTISED_10baseT_Half);
|
||||
cmd->port = PORT_OTHER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (phy == NULL) {
|
||||
pr_err("%s: %s: PHY is not registered\n",
|
||||
__func__, dev->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!netif_running(dev)) {
|
||||
pr_err("%s: interface is disabled: we cannot track "
|
||||
"link speed / duplex setting\n", dev->name);
|
||||
return -EBUSY;
|
||||
}
|
||||
cmd->transceiver = XCVR_INTERNAL;
|
||||
spin_lock_irq(&priv->lock);
|
||||
rc = phy_ethtool_gset(phy, cmd);
|
||||
spin_unlock_irq(&priv->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_setsettings(struct net_device *dev,
|
||||
struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
struct phy_device *phy = priv->phydev;
|
||||
int rc;
|
||||
|
||||
if ((priv->pcs & STMMAC_PCS_RGMII) || (priv->pcs & STMMAC_PCS_SGMII)) {
|
||||
u32 mask = ADVERTISED_Autoneg | ADVERTISED_Pause;
|
||||
|
||||
/* Only support ANE */
|
||||
if (cmd->autoneg != AUTONEG_ENABLE)
|
||||
return -EINVAL;
|
||||
|
||||
if (cmd->autoneg == AUTONEG_ENABLE) {
|
||||
mask &= (ADVERTISED_1000baseT_Half |
|
||||
ADVERTISED_1000baseT_Full |
|
||||
ADVERTISED_100baseT_Half |
|
||||
ADVERTISED_100baseT_Full |
|
||||
ADVERTISED_10baseT_Half |
|
||||
ADVERTISED_10baseT_Full);
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
if (priv->hw->mac->ctrl_ane)
|
||||
priv->hw->mac->ctrl_ane(priv->ioaddr, 1);
|
||||
spin_unlock(&priv->lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
rc = phy_ethtool_sset(phy, cmd);
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static u32 stmmac_ethtool_getmsglevel(struct net_device *dev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
return priv->msg_enable;
|
||||
}
|
||||
|
||||
static void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
priv->msg_enable = level;
|
||||
|
||||
}
|
||||
|
||||
static int stmmac_check_if_running(struct net_device *dev)
|
||||
{
|
||||
if (!netif_running(dev))
|
||||
return -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_get_regs_len(struct net_device *dev)
|
||||
{
|
||||
return REG_SPACE_SIZE;
|
||||
}
|
||||
|
||||
static void stmmac_ethtool_gregs(struct net_device *dev,
|
||||
struct ethtool_regs *regs, void *space)
|
||||
{
|
||||
int i;
|
||||
u32 *reg_space = (u32 *) space;
|
||||
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
memset(reg_space, 0x0, REG_SPACE_SIZE);
|
||||
|
||||
if (!priv->plat->has_gmac) {
|
||||
/* MAC registers */
|
||||
for (i = 0; i < 12; i++)
|
||||
reg_space[i] = readl(priv->ioaddr + (i * 4));
|
||||
/* DMA registers */
|
||||
for (i = 0; i < 9; i++)
|
||||
reg_space[i + 12] =
|
||||
readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
|
||||
reg_space[22] = readl(priv->ioaddr + DMA_CUR_TX_BUF_ADDR);
|
||||
reg_space[23] = readl(priv->ioaddr + DMA_CUR_RX_BUF_ADDR);
|
||||
} else {
|
||||
/* MAC registers */
|
||||
for (i = 0; i < 55; i++)
|
||||
reg_space[i] = readl(priv->ioaddr + (i * 4));
|
||||
/* DMA registers */
|
||||
for (i = 0; i < 22; i++)
|
||||
reg_space[i + 55] =
|
||||
readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stmmac_get_pauseparam(struct net_device *netdev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
|
||||
if (priv->pcs) /* FIXME */
|
||||
return;
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
pause->rx_pause = 0;
|
||||
pause->tx_pause = 0;
|
||||
pause->autoneg = priv->phydev->autoneg;
|
||||
|
||||
if (priv->flow_ctrl & FLOW_RX)
|
||||
pause->rx_pause = 1;
|
||||
if (priv->flow_ctrl & FLOW_TX)
|
||||
pause->tx_pause = 1;
|
||||
|
||||
spin_unlock(&priv->lock);
|
||||
}
|
||||
|
||||
static int
|
||||
stmmac_set_pauseparam(struct net_device *netdev,
|
||||
struct ethtool_pauseparam *pause)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
struct phy_device *phy = priv->phydev;
|
||||
int new_pause = FLOW_OFF;
|
||||
int ret = 0;
|
||||
|
||||
if (priv->pcs) /* FIXME */
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
|
||||
if (pause->rx_pause)
|
||||
new_pause |= FLOW_RX;
|
||||
if (pause->tx_pause)
|
||||
new_pause |= FLOW_TX;
|
||||
|
||||
priv->flow_ctrl = new_pause;
|
||||
phy->autoneg = pause->autoneg;
|
||||
|
||||
if (phy->autoneg) {
|
||||
if (netif_running(netdev))
|
||||
ret = phy_start_aneg(phy);
|
||||
} else
|
||||
priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex,
|
||||
priv->flow_ctrl, priv->pause);
|
||||
spin_unlock(&priv->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stmmac_get_ethtool_stats(struct net_device *dev,
|
||||
struct ethtool_stats *dummy, u64 *data)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
int i, j = 0;
|
||||
|
||||
/* Update the DMA HW counters for dwmac10/100 */
|
||||
if (!priv->plat->has_gmac)
|
||||
priv->hw->dma->dma_diagnostic_fr(&dev->stats,
|
||||
(void *) &priv->xstats,
|
||||
priv->ioaddr);
|
||||
else {
|
||||
/* If supported, for new GMAC chips expose the MMC counters */
|
||||
if (priv->dma_cap.rmon) {
|
||||
dwmac_mmc_read(priv->ioaddr, &priv->mmc);
|
||||
|
||||
for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
|
||||
char *p;
|
||||
p = (char *)priv + stmmac_mmc[i].stat_offset;
|
||||
|
||||
data[j++] = (stmmac_mmc[i].sizeof_stat ==
|
||||
sizeof(u64)) ? (*(u64 *)p) :
|
||||
(*(u32 *)p);
|
||||
}
|
||||
}
|
||||
if (priv->eee_enabled) {
|
||||
int val = phy_get_eee_err(priv->phydev);
|
||||
if (val)
|
||||
priv->xstats.phy_eee_wakeup_error_n = val;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < STMMAC_STATS_LEN; i++) {
|
||||
char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
|
||||
data[j++] = (stmmac_gstrings_stats[i].sizeof_stat ==
|
||||
sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
|
||||
}
|
||||
}
|
||||
|
||||
static int stmmac_get_sset_count(struct net_device *netdev, int sset)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(netdev);
|
||||
int len;
|
||||
|
||||
switch (sset) {
|
||||
case ETH_SS_STATS:
|
||||
len = STMMAC_STATS_LEN;
|
||||
|
||||
if (priv->dma_cap.rmon)
|
||||
len += STMMAC_MMC_STATS_LEN;
|
||||
|
||||
return len;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
|
||||
{
|
||||
int i;
|
||||
u8 *p = data;
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
switch (stringset) {
|
||||
case ETH_SS_STATS:
|
||||
if (priv->dma_cap.rmon)
|
||||
for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
|
||||
memcpy(p, stmmac_mmc[i].stat_string,
|
||||
ETH_GSTRING_LEN);
|
||||
p += ETH_GSTRING_LEN;
|
||||
}
|
||||
for (i = 0; i < STMMAC_STATS_LEN; i++) {
|
||||
memcpy(p, stmmac_gstrings_stats[i].stat_string,
|
||||
ETH_GSTRING_LEN);
|
||||
p += ETH_GSTRING_LEN;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Currently only support WOL through Magic packet. */
|
||||
static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
spin_lock_irq(&priv->lock);
|
||||
if (device_can_wakeup(priv->device)) {
|
||||
wol->supported = WAKE_MAGIC | WAKE_UCAST;
|
||||
wol->wolopts = priv->wolopts;
|
||||
}
|
||||
spin_unlock_irq(&priv->lock);
|
||||
}
|
||||
|
||||
static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
u32 support = WAKE_MAGIC | WAKE_UCAST;
|
||||
|
||||
/* By default almost all GMAC devices support the WoL via
|
||||
* magic frame but we can disable it if the HW capability
|
||||
* register shows no support for pmt_magic_frame. */
|
||||
if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame))
|
||||
wol->wolopts &= ~WAKE_MAGIC;
|
||||
|
||||
if (!device_can_wakeup(priv->device))
|
||||
return -EINVAL;
|
||||
|
||||
if (wol->wolopts & ~support)
|
||||
return -EINVAL;
|
||||
|
||||
if (wol->wolopts) {
|
||||
pr_info("stmmac: wakeup enable\n");
|
||||
device_set_wakeup_enable(priv->device, 1);
|
||||
enable_irq_wake(priv->wol_irq);
|
||||
} else {
|
||||
device_set_wakeup_enable(priv->device, 0);
|
||||
disable_irq_wake(priv->wol_irq);
|
||||
}
|
||||
|
||||
spin_lock_irq(&priv->lock);
|
||||
priv->wolopts = wol->wolopts;
|
||||
spin_unlock_irq(&priv->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_op_get_eee(struct net_device *dev,
|
||||
struct ethtool_eee *edata)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if (!priv->dma_cap.eee)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
edata->eee_enabled = priv->eee_enabled;
|
||||
edata->eee_active = priv->eee_active;
|
||||
edata->tx_lpi_timer = priv->tx_lpi_timer;
|
||||
|
||||
return phy_ethtool_get_eee(priv->phydev, edata);
|
||||
}
|
||||
|
||||
static int stmmac_ethtool_op_set_eee(struct net_device *dev,
|
||||
struct ethtool_eee *edata)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
priv->eee_enabled = edata->eee_enabled;
|
||||
|
||||
if (!priv->eee_enabled)
|
||||
stmmac_disable_eee_mode(priv);
|
||||
else {
|
||||
/* We are asking for enabling the EEE but it is safe
|
||||
* to verify all by invoking the eee_init function.
|
||||
* In case of failure it will return an error.
|
||||
*/
|
||||
priv->eee_enabled = stmmac_eee_init(priv);
|
||||
if (!priv->eee_enabled)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Do not change tx_lpi_timer in case of failure */
|
||||
priv->tx_lpi_timer = edata->tx_lpi_timer;
|
||||
}
|
||||
|
||||
return phy_ethtool_set_eee(priv->phydev, edata);
|
||||
}
|
||||
|
||||
static u32 stmmac_usec2riwt(u32 usec, struct stmmac_priv *priv)
|
||||
{
|
||||
unsigned long clk = clk_get_rate(priv->stmmac_clk);
|
||||
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
return (usec * (clk / 1000000)) / 256;
|
||||
}
|
||||
|
||||
static u32 stmmac_riwt2usec(u32 riwt, struct stmmac_priv *priv)
|
||||
{
|
||||
unsigned long clk = clk_get_rate(priv->stmmac_clk);
|
||||
|
||||
if (!clk)
|
||||
return 0;
|
||||
|
||||
return (riwt * 256) / (clk / 1000000);
|
||||
}
|
||||
|
||||
static int stmmac_get_coalesce(struct net_device *dev,
|
||||
struct ethtool_coalesce *ec)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
ec->tx_coalesce_usecs = priv->tx_coal_timer;
|
||||
ec->tx_max_coalesced_frames = priv->tx_coal_frames;
|
||||
|
||||
if (priv->use_riwt)
|
||||
ec->rx_coalesce_usecs = stmmac_riwt2usec(priv->rx_riwt, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_set_coalesce(struct net_device *dev,
|
||||
struct ethtool_coalesce *ec)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
unsigned int rx_riwt;
|
||||
|
||||
/* Check not supported parameters */
|
||||
if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) ||
|
||||
(ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) ||
|
||||
(ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) ||
|
||||
(ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) ||
|
||||
(ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) ||
|
||||
(ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) ||
|
||||
(ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) ||
|
||||
(ec->rx_max_coalesced_frames_high) ||
|
||||
(ec->tx_max_coalesced_frames_irq) ||
|
||||
(ec->stats_block_coalesce_usecs) ||
|
||||
(ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ec->rx_coalesce_usecs == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((ec->tx_coalesce_usecs == 0) &&
|
||||
(ec->tx_max_coalesced_frames == 0))
|
||||
return -EINVAL;
|
||||
|
||||
if ((ec->tx_coalesce_usecs > STMMAC_COAL_TX_TIMER) ||
|
||||
(ec->tx_max_coalesced_frames > STMMAC_TX_MAX_FRAMES))
|
||||
return -EINVAL;
|
||||
|
||||
rx_riwt = stmmac_usec2riwt(ec->rx_coalesce_usecs, priv);
|
||||
|
||||
if ((rx_riwt > MAX_DMA_RIWT) || (rx_riwt < MIN_DMA_RIWT))
|
||||
return -EINVAL;
|
||||
else if (!priv->use_riwt)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Only copy relevant parameters, ignore all others. */
|
||||
priv->tx_coal_frames = ec->tx_max_coalesced_frames;
|
||||
priv->tx_coal_timer = ec->tx_coalesce_usecs;
|
||||
priv->rx_riwt = rx_riwt;
|
||||
priv->hw->dma->rx_watchdog(priv->ioaddr, priv->rx_riwt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_get_ts_info(struct net_device *dev,
|
||||
struct ethtool_ts_info *info)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(dev);
|
||||
|
||||
if ((priv->hwts_tx_en) && (priv->hwts_rx_en)) {
|
||||
|
||||
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||
|
||||
if (priv->ptp_clock)
|
||||
info->phc_index = ptp_clock_index(priv->ptp_clock);
|
||||
|
||||
info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
|
||||
|
||||
info->rx_filters = ((1 << HWTSTAMP_FILTER_NONE) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
|
||||
(1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
|
||||
(1 << HWTSTAMP_FILTER_ALL));
|
||||
return 0;
|
||||
} else
|
||||
return ethtool_op_get_ts_info(dev, info);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops stmmac_ethtool_ops = {
|
||||
.begin = stmmac_check_if_running,
|
||||
.get_drvinfo = stmmac_ethtool_getdrvinfo,
|
||||
.get_settings = stmmac_ethtool_getsettings,
|
||||
.set_settings = stmmac_ethtool_setsettings,
|
||||
.get_msglevel = stmmac_ethtool_getmsglevel,
|
||||
.set_msglevel = stmmac_ethtool_setmsglevel,
|
||||
.get_regs = stmmac_ethtool_gregs,
|
||||
.get_regs_len = stmmac_ethtool_get_regs_len,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_pauseparam = stmmac_get_pauseparam,
|
||||
.set_pauseparam = stmmac_set_pauseparam,
|
||||
.get_ethtool_stats = stmmac_get_ethtool_stats,
|
||||
.get_strings = stmmac_get_strings,
|
||||
.get_wol = stmmac_get_wol,
|
||||
.set_wol = stmmac_set_wol,
|
||||
.get_eee = stmmac_ethtool_op_get_eee,
|
||||
.set_eee = stmmac_ethtool_op_set_eee,
|
||||
.get_sset_count = stmmac_get_sset_count,
|
||||
.get_ts_info = stmmac_get_ts_info,
|
||||
.get_coalesce = stmmac_get_coalesce,
|
||||
.set_coalesce = stmmac_set_coalesce,
|
||||
};
|
||||
|
||||
void stmmac_set_ethtool_ops(struct net_device *netdev)
|
||||
{
|
||||
SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops);
|
||||
}
|
||||
148
drivers/net/ethernet/rockchip/gmac/stmmac_hwtstamp.c
Executable file
148
drivers/net/ethernet/rockchip/gmac/stmmac_hwtstamp.c
Executable file
@@ -0,0 +1,148 @@
|
||||
/*******************************************************************************
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
This implements all the API for managing HW timestamp & PTP.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
#include "common.h"
|
||||
#include "stmmac_ptp.h"
|
||||
|
||||
static void stmmac_config_hw_tstamping(void __iomem *ioaddr, u32 data)
|
||||
{
|
||||
writel(data, ioaddr + PTP_TCR);
|
||||
}
|
||||
|
||||
static void stmmac_config_sub_second_increment(void __iomem *ioaddr)
|
||||
{
|
||||
u32 value = readl(ioaddr + PTP_TCR);
|
||||
unsigned long data;
|
||||
|
||||
/* Convert the ptp_clock to nano second
|
||||
* formula = (1/ptp_clock) * 1000000000
|
||||
* where, ptp_clock = 50MHz.
|
||||
*/
|
||||
data = (1000000000ULL / 50000000);
|
||||
|
||||
/* 0.465ns accuracy */
|
||||
if (value & PTP_TCR_TSCTRLSSR)
|
||||
data = (data * 100) / 465;
|
||||
|
||||
writel(data, ioaddr + PTP_SSIR);
|
||||
}
|
||||
|
||||
static int stmmac_init_systime(void __iomem *ioaddr, u32 sec, u32 nsec)
|
||||
{
|
||||
int limit;
|
||||
u32 value;
|
||||
|
||||
writel(sec, ioaddr + PTP_STSUR);
|
||||
writel(nsec, ioaddr + PTP_STNSUR);
|
||||
/* issue command to initialize the system time value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSINIT;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present system time initialize to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_config_addend(void __iomem *ioaddr, u32 addend)
|
||||
{
|
||||
u32 value;
|
||||
int limit;
|
||||
|
||||
writel(addend, ioaddr + PTP_TAR);
|
||||
/* issue command to update the addend value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSADDREG;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present addend update to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec,
|
||||
int add_sub)
|
||||
{
|
||||
u32 value;
|
||||
int limit;
|
||||
|
||||
writel(sec, ioaddr + PTP_STSUR);
|
||||
writel(((add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec),
|
||||
ioaddr + PTP_STNSUR);
|
||||
/* issue command to initialize the system time value */
|
||||
value = readl(ioaddr + PTP_TCR);
|
||||
value |= PTP_TCR_TSUPDT;
|
||||
writel(value, ioaddr + PTP_TCR);
|
||||
|
||||
/* wait for present system time adjust/update to complete */
|
||||
limit = 10;
|
||||
while (limit--) {
|
||||
if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT))
|
||||
break;
|
||||
mdelay(10);
|
||||
}
|
||||
if (limit < 0)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 stmmac_get_systime(void __iomem *ioaddr)
|
||||
{
|
||||
u64 ns;
|
||||
|
||||
ns = readl(ioaddr + PTP_STNSR);
|
||||
/* convert sec time value to nanosecond */
|
||||
ns += readl(ioaddr + PTP_STSR) * 1000000000ULL;
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
const struct stmmac_hwtimestamp stmmac_ptp = {
|
||||
.config_hw_tstamping = stmmac_config_hw_tstamping,
|
||||
.init_systime = stmmac_init_systime,
|
||||
.config_sub_second_increment = stmmac_config_sub_second_increment,
|
||||
.config_addend = stmmac_config_addend,
|
||||
.adjust_systime = stmmac_adjust_systime,
|
||||
.get_systime = stmmac_get_systime,
|
||||
};
|
||||
2956
drivers/net/ethernet/rockchip/gmac/stmmac_main.c
Executable file
2956
drivers/net/ethernet/rockchip/gmac/stmmac_main.c
Executable file
File diff suppressed because it is too large
Load Diff
270
drivers/net/ethernet/rockchip/gmac/stmmac_mdio.c
Executable file
270
drivers/net/ethernet/rockchip/gmac/stmmac_mdio.c
Executable file
@@ -0,0 +1,270 @@
|
||||
/*******************************************************************************
|
||||
STMMAC Ethernet Driver -- MDIO bus implementation
|
||||
Provides Bus interface for MII registers
|
||||
|
||||
Copyright (C) 2007-2009 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Carl Shaw <carl.shaw@st.com>
|
||||
Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "stmmac.h"
|
||||
|
||||
#define MII_BUSY 0x00000001
|
||||
#define MII_WRITE 0x00000002
|
||||
|
||||
static int stmmac_mdio_busy_wait(void __iomem *ioaddr, unsigned int mii_addr)
|
||||
{
|
||||
unsigned long curr;
|
||||
unsigned long finish = jiffies + 3 * HZ;
|
||||
|
||||
do {
|
||||
curr = jiffies;
|
||||
if (readl(ioaddr + mii_addr) & MII_BUSY)
|
||||
cpu_relax();
|
||||
else
|
||||
return 0;
|
||||
} while (!time_after_eq(curr, finish));
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_read
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr reg bits 15-11
|
||||
* @phyreg: MII addr reg bits 10-6
|
||||
* Description: it reads data from the MII register from within the phy device.
|
||||
* For the 7111 GMAC, we must set the bit 0 in the MII address register while
|
||||
* accessing the PHY registers.
|
||||
* Fortunately, it seems this has no drawback for the 7109 MAC.
|
||||
*/
|
||||
static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
|
||||
int data;
|
||||
u16 regValue = (((phyaddr << 11) & (0x0000F800)) |
|
||||
((phyreg << 6) & (0x000007C0)));
|
||||
regValue |= MII_BUSY | ((priv->clk_csr & 0xF) << 2);
|
||||
|
||||
if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
|
||||
return -EBUSY;
|
||||
|
||||
writel(regValue, priv->ioaddr + mii_address);
|
||||
|
||||
if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
|
||||
return -EBUSY;
|
||||
|
||||
/* Read the data from the MII data register */
|
||||
data = (int)readl(priv->ioaddr + mii_data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_write
|
||||
* @bus: points to the mii_bus structure
|
||||
* @phyaddr: MII addr reg bits 15-11
|
||||
* @phyreg: MII addr reg bits 10-6
|
||||
* @phydata: phy data
|
||||
* Description: it writes the data into the MII register from within the device.
|
||||
*/
|
||||
static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
|
||||
u16 phydata)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
unsigned int mii_data = priv->hw->mii.data;
|
||||
|
||||
u16 value =
|
||||
(((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0)))
|
||||
| MII_WRITE;
|
||||
|
||||
value |= MII_BUSY | ((priv->clk_csr & 0xF) << 2);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
if (stmmac_mdio_busy_wait(priv->ioaddr, mii_address))
|
||||
return -EBUSY;
|
||||
|
||||
/* Set the MII address register to write */
|
||||
writel(phydata, priv->ioaddr + mii_data);
|
||||
writel(value, priv->ioaddr + mii_address);
|
||||
|
||||
/* Wait until any existing MII operation is complete */
|
||||
return stmmac_mdio_busy_wait(priv->ioaddr, mii_address);
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_reset
|
||||
* @bus: points to the mii_bus structure
|
||||
* Description: reset the MII bus
|
||||
*/
|
||||
static int stmmac_mdio_reset(struct mii_bus *bus)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
unsigned int mii_address = priv->hw->mii.addr;
|
||||
|
||||
if (priv->plat->mdio_bus_data->phy_reset) {
|
||||
pr_debug("stmmac_mdio_reset: calling phy_reset\n");
|
||||
priv->plat->mdio_bus_data->phy_reset(priv->plat->bsp_priv);
|
||||
}
|
||||
|
||||
/* This is a workaround for problems with the STE101P PHY.
|
||||
* It doesn't complete its reset until at least one clock cycle
|
||||
* on MDC, so perform a dummy mdio read.
|
||||
*/
|
||||
writel(0, priv->ioaddr + mii_address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_register
|
||||
* @ndev: net device structure
|
||||
* Description: it registers the MII bus
|
||||
*/
|
||||
int stmmac_mdio_register(struct net_device *ndev)
|
||||
{
|
||||
int err = 0;
|
||||
struct mii_bus *new_bus;
|
||||
int *irqlist;
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
struct stmmac_mdio_bus_data *mdio_bus_data = priv->plat->mdio_bus_data;
|
||||
int addr, found;
|
||||
|
||||
if (!mdio_bus_data)
|
||||
return 0;
|
||||
|
||||
new_bus = mdiobus_alloc();
|
||||
if (new_bus == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mdio_bus_data->irqs)
|
||||
irqlist = mdio_bus_data->irqs;
|
||||
else
|
||||
irqlist = priv->mii_irq;
|
||||
|
||||
new_bus->name = "stmmac";
|
||||
new_bus->read = &stmmac_mdio_read;
|
||||
new_bus->write = &stmmac_mdio_write;
|
||||
new_bus->reset = &stmmac_mdio_reset;
|
||||
snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s-%x",
|
||||
new_bus->name, priv->plat->bus_id);
|
||||
new_bus->priv = ndev;
|
||||
new_bus->irq = irqlist;
|
||||
new_bus->phy_mask = mdio_bus_data->phy_mask;
|
||||
new_bus->parent = priv->device;
|
||||
err = mdiobus_register(new_bus);
|
||||
if (err != 0) {
|
||||
pr_err("%s: Cannot register as MDIO bus\n", new_bus->name);
|
||||
goto bus_register_fail;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
|
||||
struct phy_device *phydev = new_bus->phy_map[addr];
|
||||
if (phydev) {
|
||||
int act = 0;
|
||||
char irq_num[4];
|
||||
char *irq_str;
|
||||
|
||||
/*
|
||||
* If an IRQ was provided to be assigned after
|
||||
* the bus probe, do it here.
|
||||
*/
|
||||
if ((mdio_bus_data->irqs == NULL) &&
|
||||
(mdio_bus_data->probed_phy_irq > 0)) {
|
||||
irqlist[addr] = mdio_bus_data->probed_phy_irq;
|
||||
phydev->irq = mdio_bus_data->probed_phy_irq;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're going to bind the MAC to this PHY bus,
|
||||
* and no PHY number was provided to the MAC,
|
||||
* use the one probed here.
|
||||
*/
|
||||
if (priv->plat->phy_addr == -1)
|
||||
priv->plat->phy_addr = addr;
|
||||
|
||||
act = (priv->plat->phy_addr == addr);
|
||||
switch (phydev->irq) {
|
||||
case PHY_POLL:
|
||||
irq_str = "POLL";
|
||||
break;
|
||||
case PHY_IGNORE_INTERRUPT:
|
||||
irq_str = "IGNORE";
|
||||
break;
|
||||
default:
|
||||
sprintf(irq_num, "%d", phydev->irq);
|
||||
irq_str = irq_num;
|
||||
break;
|
||||
}
|
||||
pr_info("%s: PHY ID %08x at %d IRQ %s (%s)%s\n",
|
||||
ndev->name, phydev->phy_id, addr,
|
||||
irq_str, dev_name(&phydev->dev),
|
||||
act ? " active" : "");
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
pr_warning("%s: No PHY found\n", ndev->name);
|
||||
mdiobus_unregister(new_bus);
|
||||
mdiobus_free(new_bus);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->mii = new_bus;
|
||||
|
||||
return 0;
|
||||
|
||||
bus_register_fail:
|
||||
mdiobus_free(new_bus);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_unregister
|
||||
* @ndev: net device structure
|
||||
* Description: it unregisters the MII bus
|
||||
*/
|
||||
int stmmac_mdio_unregister(struct net_device *ndev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
if (!priv->mii)
|
||||
return 0;
|
||||
|
||||
mdiobus_unregister(priv->mii);
|
||||
priv->mii->priv = NULL;
|
||||
mdiobus_free(priv->mii);
|
||||
priv->mii = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
196
drivers/net/ethernet/rockchip/gmac/stmmac_pci.c
Executable file
196
drivers/net/ethernet/rockchip/gmac/stmmac_pci.c
Executable file
@@ -0,0 +1,196 @@
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the pci driver.
|
||||
|
||||
Copyright (C) 2011-2012 Vayavya Labs Pvt Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include "stmmac.h"
|
||||
|
||||
struct plat_stmmacenet_data plat_dat;
|
||||
struct stmmac_mdio_bus_data mdio_data;
|
||||
struct stmmac_dma_cfg dma_cfg;
|
||||
|
||||
static void stmmac_default_data(void)
|
||||
{
|
||||
memset(&plat_dat, 0, sizeof(struct plat_stmmacenet_data));
|
||||
plat_dat.bus_id = 1;
|
||||
plat_dat.phy_addr = 0;
|
||||
plat_dat.interface = PHY_INTERFACE_MODE_GMII;
|
||||
plat_dat.clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
|
||||
plat_dat.has_gmac = 1;
|
||||
plat_dat.force_sf_dma_mode = 1;
|
||||
|
||||
mdio_data.phy_reset = NULL;
|
||||
mdio_data.phy_mask = 0;
|
||||
plat_dat.mdio_bus_data = &mdio_data;
|
||||
|
||||
dma_cfg.pbl = 32;
|
||||
dma_cfg.burst_len = DMA_AXI_BLEN_256;
|
||||
plat_dat.dma_cfg = &dma_cfg;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_pci_probe
|
||||
*
|
||||
* @pdev: pci device pointer
|
||||
* @id: pointer to table of device id/id's.
|
||||
*
|
||||
* Description: This probing function gets called for all PCI devices which
|
||||
* match the ID table and are not "owned" by other driver yet. This function
|
||||
* gets passed a "struct pci_dev *" for each device whose entry in the ID table
|
||||
* matches the device. The probe functions returns zero when the driver choose
|
||||
* to take "ownership" of the device or an error code(-ve no) otherwise.
|
||||
*/
|
||||
static int stmmac_pci_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
int ret = 0;
|
||||
void __iomem *addr = NULL;
|
||||
struct stmmac_priv *priv = NULL;
|
||||
int i;
|
||||
|
||||
/* Enable pci device */
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
pr_err("%s : ERROR: failed to enable %s device\n", __func__,
|
||||
pci_name(pdev));
|
||||
return ret;
|
||||
}
|
||||
if (pci_request_regions(pdev, STMMAC_RESOURCE_NAME)) {
|
||||
pr_err("%s: ERROR: failed to get PCI region\n", __func__);
|
||||
ret = -ENODEV;
|
||||
goto err_out_req_reg_failed;
|
||||
}
|
||||
|
||||
/* Get the base address of device */
|
||||
for (i = 0; i <= 5; i++) {
|
||||
if (pci_resource_len(pdev, i) == 0)
|
||||
continue;
|
||||
addr = pci_iomap(pdev, i, 0);
|
||||
if (addr == NULL) {
|
||||
pr_err("%s: ERROR: cannot map register memory aborting",
|
||||
__func__);
|
||||
ret = -EIO;
|
||||
goto err_out_map_failed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pci_set_master(pdev);
|
||||
|
||||
stmmac_default_data();
|
||||
|
||||
priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
|
||||
if (!priv) {
|
||||
pr_err("%s: main driver probe failed", __func__);
|
||||
ret = -ENODEV;
|
||||
goto err_out;
|
||||
}
|
||||
priv->dev->irq = pdev->irq;
|
||||
priv->wol_irq = pdev->irq;
|
||||
|
||||
pci_set_drvdata(pdev, priv->dev);
|
||||
|
||||
pr_debug("STMMAC platform driver registration completed");
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
pci_clear_master(pdev);
|
||||
err_out_map_failed:
|
||||
pci_release_regions(pdev);
|
||||
err_out_req_reg_failed:
|
||||
pci_disable_device(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_pci_remove
|
||||
*
|
||||
* @pdev: platform device pointer
|
||||
* Description: this function calls the main to free the net resources
|
||||
* and releases the PCI resources.
|
||||
*/
|
||||
static void stmmac_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *ndev = pci_get_drvdata(pdev);
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
stmmac_dvr_remove(ndev);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
pci_iounmap(pdev, priv->ioaddr);
|
||||
pci_release_regions(pdev);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int stmmac_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
{
|
||||
struct net_device *ndev = pci_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = stmmac_suspend(ndev);
|
||||
pci_save_state(pdev);
|
||||
pci_set_power_state(pdev, pci_choose_state(pdev, state));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmmac_pci_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct net_device *ndev = pci_get_drvdata(pdev);
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
|
||||
return stmmac_resume(ndev);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define STMMAC_VENDOR_ID 0x700
|
||||
#define STMMAC_DEVICE_ID 0x1108
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(stmmac_id_table) = {
|
||||
{PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)},
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, stmmac_id_table);
|
||||
|
||||
struct pci_driver stmmac_pci_driver = {
|
||||
.name = STMMAC_RESOURCE_NAME,
|
||||
.id_table = stmmac_id_table,
|
||||
.probe = stmmac_pci_probe,
|
||||
.remove = stmmac_pci_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = stmmac_pci_suspend,
|
||||
.resume = stmmac_pci_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PCI driver");
|
||||
MODULE_AUTHOR("Rayagond Kokatanur <rayagond.kokatanur@vayavyalabs.com>");
|
||||
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
252
drivers/net/ethernet/rockchip/gmac/stmmac_platform.c
Executable file
252
drivers/net/ethernet/rockchip/gmac/stmmac_platform.c
Executable file
@@ -0,0 +1,252 @@
|
||||
/*******************************************************************************
|
||||
This contains the functions to handle the platform driver.
|
||||
|
||||
Copyright (C) 2007-2011 STMicroelectronics Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||
*******************************************************************************/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_net.h>
|
||||
#include "stmmac.h"
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int stmmac_probe_config_dt(struct platform_device *pdev,
|
||||
struct plat_stmmacenet_data *plat,
|
||||
const char **mac)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
*mac = of_get_mac_address(np);
|
||||
plat->interface = of_get_phy_mode(np);
|
||||
plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct stmmac_mdio_bus_data),
|
||||
GFP_KERNEL);
|
||||
|
||||
/*
|
||||
* Currently only the properties needed on SPEAr600
|
||||
* are provided. All other properties should be added
|
||||
* once needed on other platforms.
|
||||
*/
|
||||
if (of_device_is_compatible(np, "st,spear600-gmac") ||
|
||||
of_device_is_compatible(np, "snps,dwmac-3.70a") ||
|
||||
of_device_is_compatible(np, "snps,dwmac")) {
|
||||
plat->has_gmac = 1;
|
||||
plat->pmt = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int stmmac_probe_config_dt(struct platform_device *pdev,
|
||||
struct plat_stmmacenet_data *plat,
|
||||
const char **mac)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/**
|
||||
* stmmac_pltfr_probe
|
||||
* @pdev: platform device pointer
|
||||
* Description: platform_device probe function. It allocates
|
||||
* the necessary resources and invokes the main to init
|
||||
* the net device, register the mdio bus etc.
|
||||
*/
|
||||
static int stmmac_pltfr_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *addr = NULL;
|
||||
struct stmmac_priv *priv = NULL;
|
||||
struct plat_stmmacenet_data *plat_dat = NULL;
|
||||
const char *mac = NULL;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
addr = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(addr))
|
||||
return PTR_ERR(addr);
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
plat_dat = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct plat_stmmacenet_data),
|
||||
GFP_KERNEL);
|
||||
if (!plat_dat) {
|
||||
pr_err("%s: ERROR: no memory", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
|
||||
if (ret) {
|
||||
pr_err("%s: main dt probe failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
plat_dat = pdev->dev.platform_data;
|
||||
}
|
||||
|
||||
/* Custom initialisation (if needed)*/
|
||||
if (plat_dat->init) {
|
||||
ret = plat_dat->init(pdev);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
|
||||
if (!priv) {
|
||||
pr_err("%s: main driver probe failed", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Get MAC address if available (DT) */
|
||||
if (mac)
|
||||
memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
|
||||
|
||||
/* Get the MAC information */
|
||||
priv->dev->irq = platform_get_irq_byname(pdev, "macirq");
|
||||
if (priv->dev->irq == -ENXIO) {
|
||||
pr_err("%s: ERROR: MAC IRQ configuration "
|
||||
"information not found\n", __func__);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
|
||||
* The external wake up irq can be passed through the platform code
|
||||
* named as "eth_wake_irq"
|
||||
*
|
||||
* In case the wake up interrupt is not passed from the platform
|
||||
* so the driver will continue to use the mac irq (ndev->irq)
|
||||
*/
|
||||
priv->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
|
||||
if (priv->wol_irq == -ENXIO)
|
||||
priv->wol_irq = priv->dev->irq;
|
||||
|
||||
priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
|
||||
|
||||
platform_set_drvdata(pdev, priv->dev);
|
||||
|
||||
pr_debug("STMMAC platform driver registration completed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_pltfr_remove
|
||||
* @pdev: platform device pointer
|
||||
* Description: this function calls the main to free the net resources
|
||||
* and calls the platforms hook and release the resources (e.g. mem).
|
||||
*/
|
||||
static int stmmac_pltfr_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *ndev = platform_get_drvdata(pdev);
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
int ret = stmmac_dvr_remove(ndev);
|
||||
|
||||
if (priv->plat->exit)
|
||||
priv->plat->exit(pdev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int stmmac_pltfr_suspend(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
|
||||
return stmmac_suspend(ndev);
|
||||
}
|
||||
|
||||
static int stmmac_pltfr_resume(struct device *dev)
|
||||
{
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
|
||||
return stmmac_resume(ndev);
|
||||
}
|
||||
|
||||
int stmmac_pltfr_freeze(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev);
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
ret = stmmac_freeze(ndev);
|
||||
if (plat_dat->exit)
|
||||
plat_dat->exit(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int stmmac_pltfr_restore(struct device *dev)
|
||||
{
|
||||
struct plat_stmmacenet_data *plat_dat = dev_get_platdata(dev);
|
||||
struct net_device *ndev = dev_get_drvdata(dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
if (plat_dat->init)
|
||||
plat_dat->init(pdev);
|
||||
|
||||
return stmmac_restore(ndev);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops stmmac_pltfr_pm_ops = {
|
||||
.suspend = stmmac_pltfr_suspend,
|
||||
.resume = stmmac_pltfr_resume,
|
||||
.freeze = stmmac_pltfr_freeze,
|
||||
.thaw = stmmac_pltfr_restore,
|
||||
.restore = stmmac_pltfr_restore,
|
||||
};
|
||||
#else
|
||||
static const struct dev_pm_ops stmmac_pltfr_pm_ops;
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct of_device_id stmmac_dt_ids[] = {
|
||||
{ .compatible = "st,spear600-gmac"},
|
||||
{ .compatible = "snps,dwmac-3.70a"},
|
||||
{ .compatible = "snps,dwmac"},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stmmac_dt_ids);
|
||||
|
||||
struct platform_driver stmmac_pltfr_driver = {
|
||||
.probe = stmmac_pltfr_probe,
|
||||
.remove = stmmac_pltfr_remove,
|
||||
.driver = {
|
||||
.name = STMMAC_RESOURCE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &stmmac_pltfr_pm_ops,
|
||||
.of_match_table = of_match_ptr(stmmac_dt_ids),
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
|
||||
MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
211
drivers/net/ethernet/rockchip/gmac/stmmac_ptp.c
Executable file
211
drivers/net/ethernet/rockchip/gmac/stmmac_ptp.c
Executable file
@@ -0,0 +1,211 @@
|
||||
/*******************************************************************************
|
||||
PTP 1588 clock using the STMMAC.
|
||||
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
*******************************************************************************/
|
||||
#include "stmmac.h"
|
||||
#include "stmmac_ptp.h"
|
||||
|
||||
/**
|
||||
* stmmac_adjust_freq
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ppb: desired period change in parts ber billion
|
||||
*
|
||||
* Description: this function will adjust the frequency of hardware clock.
|
||||
*/
|
||||
static int stmmac_adjust_freq(struct ptp_clock_info *ptp, s32 ppb)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u32 diff, addend;
|
||||
int neg_adj = 0;
|
||||
u64 adj;
|
||||
|
||||
if (ppb < 0) {
|
||||
neg_adj = 1;
|
||||
ppb = -ppb;
|
||||
}
|
||||
|
||||
addend = priv->default_addend;
|
||||
adj = addend;
|
||||
adj *= ppb;
|
||||
diff = div_u64(adj, 1000000000ULL);
|
||||
addend = neg_adj ? (addend - diff) : (addend + diff);
|
||||
|
||||
spin_lock_irqsave(&priv->ptp_lock, flags);
|
||||
|
||||
priv->hw->ptp->config_addend(priv->ioaddr, addend);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_adjust_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @delta: desired change in nanoseconds
|
||||
*
|
||||
* Description: this function will shift/adjust the hardware clock time.
|
||||
*/
|
||||
static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u32 sec, nsec;
|
||||
u32 quotient, reminder;
|
||||
int neg_adj = 0;
|
||||
|
||||
if (delta < 0) {
|
||||
neg_adj = 1;
|
||||
delta = -delta;
|
||||
}
|
||||
|
||||
quotient = div_u64_rem(delta, 1000000000ULL, &reminder);
|
||||
sec = quotient;
|
||||
nsec = reminder;
|
||||
|
||||
spin_lock_irqsave(&priv->ptp_lock, flags);
|
||||
|
||||
priv->hw->ptp->adjust_systime(priv->ioaddr, sec, nsec, neg_adj);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_get_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ts: pointer to hold time/result
|
||||
*
|
||||
* Description: this function will read the current time from the
|
||||
* hardware clock and store it in @ts.
|
||||
*/
|
||||
static int stmmac_get_time(struct ptp_clock_info *ptp, struct timespec *ts)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
u64 ns;
|
||||
u32 reminder;
|
||||
|
||||
spin_lock_irqsave(&priv->ptp_lock, flags);
|
||||
|
||||
ns = priv->hw->ptp->get_systime(priv->ioaddr);
|
||||
|
||||
spin_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &reminder);
|
||||
ts->tv_nsec = reminder;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_set_time
|
||||
*
|
||||
* @ptp: pointer to ptp_clock_info structure
|
||||
* @ts: time value to set
|
||||
*
|
||||
* Description: this function will set the current time on the
|
||||
* hardware clock.
|
||||
*/
|
||||
static int stmmac_set_time(struct ptp_clock_info *ptp,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
struct stmmac_priv *priv =
|
||||
container_of(ptp, struct stmmac_priv, ptp_clock_ops);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->ptp_lock, flags);
|
||||
|
||||
priv->hw->ptp->init_systime(priv->ioaddr, ts->tv_sec, ts->tv_nsec);
|
||||
|
||||
spin_unlock_irqrestore(&priv->ptp_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* structure describing a PTP hardware clock */
|
||||
static struct ptp_clock_info stmmac_ptp_clock_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "stmmac_ptp_clock",
|
||||
.max_adj = 62500000,
|
||||
.n_alarm = 0,
|
||||
.n_ext_ts = 0,
|
||||
.n_per_out = 0,
|
||||
.pps = 0,
|
||||
.adjfreq = stmmac_adjust_freq,
|
||||
.adjtime = stmmac_adjust_time,
|
||||
.gettime = stmmac_get_time,
|
||||
.settime = stmmac_set_time,
|
||||
.enable = stmmac_enable,
|
||||
};
|
||||
|
||||
/**
|
||||
* stmmac_ptp_register
|
||||
* @priv: driver private structure
|
||||
* Description: this function will register the ptp clock driver
|
||||
* to kernel. It also does some house keeping work.
|
||||
*/
|
||||
int stmmac_ptp_register(struct stmmac_priv *priv)
|
||||
{
|
||||
spin_lock_init(&priv->ptp_lock);
|
||||
priv->ptp_clock_ops = stmmac_ptp_clock_ops;
|
||||
|
||||
priv->ptp_clock = ptp_clock_register(&priv->ptp_clock_ops,
|
||||
priv->device);
|
||||
if (IS_ERR(priv->ptp_clock)) {
|
||||
priv->ptp_clock = NULL;
|
||||
pr_err("ptp_clock_register() failed on %s\n", priv->dev->name);
|
||||
} else
|
||||
pr_debug("Added PTP HW clock successfully on %s\n",
|
||||
priv->dev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_ptp_unregister
|
||||
* @priv: driver private structure
|
||||
* Description: this function will remove/unregister the ptp clock driver
|
||||
* from the kernel.
|
||||
*/
|
||||
void stmmac_ptp_unregister(struct stmmac_priv *priv)
|
||||
{
|
||||
if (priv->ptp_clock) {
|
||||
ptp_clock_unregister(priv->ptp_clock);
|
||||
pr_debug("Removed PTP HW clock successfully on %s\n",
|
||||
priv->dev->name);
|
||||
}
|
||||
}
|
||||
74
drivers/net/ethernet/rockchip/gmac/stmmac_ptp.h
Executable file
74
drivers/net/ethernet/rockchip/gmac/stmmac_ptp.h
Executable file
@@ -0,0 +1,74 @@
|
||||
/******************************************************************************
|
||||
PTP Header file
|
||||
|
||||
Copyright (C) 2013 Vayavya Labs Pvt Ltd
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms and conditions of the GNU General Public License,
|
||||
version 2, as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
The full GNU General Public License is included in this distribution in
|
||||
the file called "COPYING".
|
||||
|
||||
Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __STMMAC_PTP_H__
|
||||
#define __STMMAC_PTP_H__
|
||||
|
||||
#define STMMAC_SYSCLOCK 62500000
|
||||
|
||||
/* IEEE 1588 PTP register offsets */
|
||||
#define PTP_TCR 0x0700 /* Timestamp Control Reg */
|
||||
#define PTP_SSIR 0x0704 /* Sub-Second Increment Reg */
|
||||
#define PTP_STSR 0x0708 /* System Time – Seconds Regr */
|
||||
#define PTP_STNSR 0x070C /* System Time – Nanoseconds Reg */
|
||||
#define PTP_STSUR 0x0710 /* System Time – Seconds Update Reg */
|
||||
#define PTP_STNSUR 0x0714 /* System Time – Nanoseconds Update Reg */
|
||||
#define PTP_TAR 0x0718 /* Timestamp Addend Reg */
|
||||
#define PTP_TTSR 0x071C /* Target Time Seconds Reg */
|
||||
#define PTP_TTNSR 0x0720 /* Target Time Nanoseconds Reg */
|
||||
#define PTP_STHWSR 0x0724 /* System Time - Higher Word Seconds Reg */
|
||||
#define PTP_TSR 0x0728 /* Timestamp Status */
|
||||
|
||||
#define PTP_STNSUR_ADDSUB_SHIFT 31
|
||||
|
||||
/* PTP TCR defines */
|
||||
#define PTP_TCR_TSENA 0x00000001 /* Timestamp Enable */
|
||||
#define PTP_TCR_TSCFUPDT 0x00000002 /* Timestamp Fine/Coarse Update */
|
||||
#define PTP_TCR_TSINIT 0x00000004 /* Timestamp Initialize */
|
||||
#define PTP_TCR_TSUPDT 0x00000008 /* Timestamp Update */
|
||||
/* Timestamp Interrupt Trigger Enable */
|
||||
#define PTP_TCR_TSTRIG 0x00000010
|
||||
#define PTP_TCR_TSADDREG 0x00000020 /* Addend Reg Update */
|
||||
#define PTP_TCR_TSENALL 0x00000100 /* Enable Timestamp for All Frames */
|
||||
/* Timestamp Digital or Binary Rollover Control */
|
||||
#define PTP_TCR_TSCTRLSSR 0x00000200
|
||||
|
||||
/* Enable PTP packet Processing for Version 2 Format */
|
||||
#define PTP_TCR_TSVER2ENA 0x00000400
|
||||
/* Enable Processing of PTP over Ethernet Frames */
|
||||
#define PTP_TCR_TSIPENA 0x00000800
|
||||
/* Enable Processing of PTP Frames Sent over IPv6-UDP */
|
||||
#define PTP_TCR_TSIPV6ENA 0x00001000
|
||||
/* Enable Processing of PTP Frames Sent over IPv4-UDP */
|
||||
#define PTP_TCR_TSIPV4ENA 0x00002000
|
||||
/* Enable Timestamp Snapshot for Event Messages */
|
||||
#define PTP_TCR_TSEVNTENA 0x00004000
|
||||
/* Enable Snapshot for Messages Relevant to Master */
|
||||
#define PTP_TCR_TSMSTRENA 0x00008000
|
||||
/* Select PTP packets for Taking Snapshots */
|
||||
#define PTP_TCR_SNAPTYPSEL_1 0x00010000
|
||||
/* Enable MAC address for PTP Frame Filtering */
|
||||
#define PTP_TCR_TSENMACADDR 0x00040000
|
||||
|
||||
#endif /* __STMMAC_PTP_H__ */
|
||||
@@ -148,14 +148,14 @@ static int vmac_phy_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static struct of_device_id vmac_phy_of_match[] = {
|
||||
{ .compatible = "vmac-phy" },
|
||||
{ .compatible = "rockchip,vmac-phy" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, vmac_phy_of_match);
|
||||
|
||||
static struct platform_driver vmac_phy_driver = {
|
||||
.driver = {
|
||||
.name = "vmac-phy",
|
||||
.name = "rockchip,vmac-phy",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(vmac_phy_of_match),
|
||||
},
|
||||
@@ -166,4 +166,4 @@ static struct platform_driver vmac_phy_driver = {
|
||||
module_platform_driver(vmac_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("VMAC PHY Power Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL");
|
||||
Reference in New Issue
Block a user