*
* U-Boot version:
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
*/
#include <common.h>
+#include <cpu_func.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <asm/arch/soc.h>
#include <linux/compat.h>
#include <linux/mbus.h>
+#include <asm-generic/gpio.h>
+#include <fdt_support.h>
DECLARE_GLOBAL_DATA_PTR;
-/* Some linux -> U-Boot compatibility stuff */
-#define netdev_err(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_warn(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_info(dev, fmt, args...) \
- printf(fmt, ##args)
-#define netdev_dbg(dev, fmt, args...) \
- printf(fmt, ##args)
-
-#define ETH_ALEN 6 /* Octets in one ethernet addr */
-
#define __verify_pcpu_ptr(ptr) \
do { \
const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL; \
#define NET_SKB_PAD max(32, MVPP2_CPU_D_CACHE_LINE_SIZE)
#define CONFIG_NR_CPUS 1
-#define ETH_HLEN ETHER_HDR_SIZE /* Total octets in header */
/* 2(HW hdr) 14(MAC hdr) 4(CRC) 32(extra for cache prefetch) */
#define WRAP (2 + ETH_HLEN + 4 + 32)
#define MVPP2_SNOOP_PKT_SIZE_MASK 0x1ff
#define MVPP2_SNOOP_BUF_HDR_MASK BIT(9)
#define MVPP2_RXQ_POOL_SHORT_OFFS 20
-#define MVPP2_RXQ_POOL_SHORT_MASK 0x700000
+#define MVPP21_RXQ_POOL_SHORT_MASK 0x700000
+#define MVPP22_RXQ_POOL_SHORT_MASK 0xf00000
#define MVPP2_RXQ_POOL_LONG_OFFS 24
-#define MVPP2_RXQ_POOL_LONG_MASK 0x7000000
+#define MVPP21_RXQ_POOL_LONG_MASK 0x7000000
+#define MVPP22_RXQ_POOL_LONG_MASK 0xf000000
#define MVPP2_RXQ_PACKET_OFFSET_OFFS 28
#define MVPP2_RXQ_PACKET_OFFSET_MASK 0x70000000
#define MVPP2_RXQ_DISABLE_MASK BIT(31)
/* Descriptor Manager Top Registers */
#define MVPP2_RXQ_NUM_REG 0x2040
#define MVPP2_RXQ_DESC_ADDR_REG 0x2044
+#define MVPP22_DESC_ADDR_OFFS 8
#define MVPP2_RXQ_DESC_SIZE_REG 0x2048
#define MVPP2_RXQ_DESC_SIZE_MASK 0x3ff0
#define MVPP2_RXQ_STATUS_UPDATE_REG(rxq) (0x3000 + 4 * (rxq))
#define MVPP2_TXQ_RSVD_CLR_REG 0x20b8
#define MVPP2_TXQ_RSVD_CLR_OFFSET 16
#define MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu) (0x2100 + 4 * (cpu))
+#define MVPP22_AGGR_TXQ_DESC_ADDR_OFFS 8
#define MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu) (0x2140 + 4 * (cpu))
#define MVPP2_AGGR_TXQ_DESC_SIZE_MASK 0x3ff0
#define MVPP2_AGGR_TXQ_STATUS_REG(cpu) (0x2180 + 4 * (cpu))
#define MVPP2_WIN_REMAP(w) (0x4040 + ((w) << 2))
#define MVPP2_BASE_ADDR_ENABLE 0x4060
+/* AXI Bridge Registers */
+#define MVPP22_AXI_BM_WR_ATTR_REG 0x4100
+#define MVPP22_AXI_BM_RD_ATTR_REG 0x4104
+#define MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG 0x4110
+#define MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG 0x4114
+#define MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG 0x4118
+#define MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG 0x411c
+#define MVPP22_AXI_RX_DATA_WR_ATTR_REG 0x4120
+#define MVPP22_AXI_TX_DATA_RD_ATTR_REG 0x4130
+#define MVPP22_AXI_RD_NORMAL_CODE_REG 0x4150
+#define MVPP22_AXI_RD_SNOOP_CODE_REG 0x4154
+#define MVPP22_AXI_WR_NORMAL_CODE_REG 0x4160
+#define MVPP22_AXI_WR_SNOOP_CODE_REG 0x4164
+
+/* Values for AXI Bridge registers */
+#define MVPP22_AXI_ATTR_CACHE_OFFS 0
+#define MVPP22_AXI_ATTR_DOMAIN_OFFS 12
+
+#define MVPP22_AXI_CODE_CACHE_OFFS 0
+#define MVPP22_AXI_CODE_DOMAIN_OFFS 4
+
+#define MVPP22_AXI_CODE_CACHE_NON_CACHE 0x3
+#define MVPP22_AXI_CODE_CACHE_WR_CACHE 0x7
+#define MVPP22_AXI_CODE_CACHE_RD_CACHE 0xb
+
+#define MVPP22_AXI_CODE_DOMAIN_OUTER_DOM 2
+#define MVPP22_AXI_CODE_DOMAIN_SYSTEM 3
+
/* Interrupt Cause and Mask registers */
#define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq))
-#define MVPP2_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq))
+#define MVPP21_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq))
+
+#define MVPP22_ISR_RXQ_GROUP_INDEX_REG 0x5400
+#define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf
+#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380
+#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET 7
+
+#define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf
+#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380
+
+#define MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG 0x5404
+#define MVPP22_ISR_RXQ_SUB_GROUP_STARTQ_MASK 0x1f
+#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_MASK 0xf00
+#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET 8
+
#define MVPP2_ISR_ENABLE_REG(port) (0x5420 + 4 * (port))
#define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff)
#define MVPP2_ISR_DISABLE_INTERRUPT(mask) (((mask) << 16) & 0xffff0000)
#define MVPP2_BM_PHY_ALLOC_REG(pool) (0x6400 + ((pool) * 4))
#define MVPP2_BM_PHY_ALLOC_GRNTD_MASK BIT(0)
#define MVPP2_BM_VIRT_ALLOC_REG 0x6440
+#define MVPP2_BM_ADDR_HIGH_ALLOC 0x6444
+#define MVPP2_BM_ADDR_HIGH_PHYS_MASK 0xff
+#define MVPP2_BM_ADDR_HIGH_VIRT_MASK 0xff00
+#define MVPP2_BM_ADDR_HIGH_VIRT_SHIFT 8
#define MVPP2_BM_PHY_RLS_REG(pool) (0x6480 + ((pool) * 4))
#define MVPP2_BM_PHY_RLS_MC_BUFF_MASK BIT(0)
#define MVPP2_BM_PHY_RLS_PRIO_EN_MASK BIT(1)
#define MVPP2_BM_PHY_RLS_GRNTD_MASK BIT(2)
#define MVPP2_BM_VIRT_RLS_REG 0x64c0
-#define MVPP2_BM_MC_RLS_REG 0x64c4
+#define MVPP21_BM_MC_RLS_REG 0x64c4
#define MVPP2_BM_MC_ID_MASK 0xfff
#define MVPP2_BM_FORCE_RELEASE_MASK BIT(12)
+#define MVPP22_BM_ADDR_HIGH_RLS_REG 0x64c4
+#define MVPP22_BM_ADDR_HIGH_PHYS_RLS_MASK 0xff
+#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK 0xff00
+#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT 8
+#define MVPP22_BM_MC_RLS_REG 0x64d4
+#define MVPP22_BM_POOL_BASE_HIGH_REG 0x6310
+#define MVPP22_BM_POOL_BASE_HIGH_MASK 0xff
/* TX Scheduler registers */
#define MVPP2_TXP_SCHED_PORT_INDEX_REG 0x8000
/* Per-port registers */
#define MVPP2_GMAC_CTRL_0_REG 0x0
#define MVPP2_GMAC_PORT_EN_MASK BIT(0)
+#define MVPP2_GMAC_PORT_TYPE_MASK BIT(1)
#define MVPP2_GMAC_MAX_RX_SIZE_OFFS 2
#define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc
#define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15)
#define MVPP2_GMAC_SA_LOW_OFFS 7
#define MVPP2_GMAC_CTRL_2_REG 0x8
#define MVPP2_GMAC_INBAND_AN_MASK BIT(0)
+#define MVPP2_GMAC_SGMII_MODE_MASK BIT(0)
#define MVPP2_GMAC_PCS_ENABLE_MASK BIT(3)
#define MVPP2_GMAC_PORT_RGMII_MASK BIT(4)
+#define MVPP2_GMAC_PORT_DIS_PADING_MASK BIT(5)
#define MVPP2_GMAC_PORT_RESET_MASK BIT(6)
+#define MVPP2_GMAC_CLK_125_BYPS_EN_MASK BIT(9)
#define MVPP2_GMAC_AUTONEG_CONFIG 0xc
#define MVPP2_GMAC_FORCE_LINK_DOWN BIT(0)
#define MVPP2_GMAC_FORCE_LINK_PASS BIT(1)
+#define MVPP2_GMAC_EN_PCS_AN BIT(2)
+#define MVPP2_GMAC_AN_BYPASS_EN BIT(3)
#define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5)
#define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6)
#define MVPP2_GMAC_AN_SPEED_EN BIT(7)
#define MVPP2_GMAC_FC_ADV_EN BIT(9)
+#define MVPP2_GMAC_EN_FC_AN BIT(11)
#define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12)
#define MVPP2_GMAC_AN_DUPLEX_EN BIT(13)
+#define MVPP2_GMAC_CHOOSE_SAMPLE_TX_CONFIG BIT(15)
#define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c
#define MVPP2_GMAC_TX_FIFO_MIN_TH_OFFS 6
#define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0
#define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & \
MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK)
+#define MVPP2_GMAC_CTRL_4_REG 0x90
+#define MVPP2_GMAC_CTRL4_EXT_PIN_GMII_SEL_MASK BIT(0)
+#define MVPP2_GMAC_CTRL4_DP_CLK_SEL_MASK BIT(5)
+#define MVPP2_GMAC_CTRL4_SYNC_BYPASS_MASK BIT(6)
+#define MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK BIT(7)
+
+/*
+ * Per-port XGMAC registers. PPv2.2 only, only for GOP port 0,
+ * relative to port->base.
+ */
+
+/* Port Mac Control0 */
+#define MVPP22_XLG_CTRL0_REG 0x100
+#define MVPP22_XLG_PORT_EN BIT(0)
+#define MVPP22_XLG_MAC_RESETN BIT(1)
+#define MVPP22_XLG_RX_FC_EN BIT(7)
+#define MVPP22_XLG_MIBCNT_DIS BIT(13)
+/* Port Mac Control1 */
+#define MVPP22_XLG_CTRL1_REG 0x104
+#define MVPP22_XLG_MAX_RX_SIZE_OFFS 0
+#define MVPP22_XLG_MAX_RX_SIZE_MASK 0x1fff
+/* Port Interrupt Mask */
+#define MVPP22_XLG_INTERRUPT_MASK_REG 0x118
+#define MVPP22_XLG_INTERRUPT_LINK_CHANGE BIT(1)
+/* Port Mac Control3 */
+#define MVPP22_XLG_CTRL3_REG 0x11c
+#define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13)
+#define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13)
+#define MVPP22_XLG_CTRL3_MACMODESELECT_10GMAC (1 << 13)
+/* Port Mac Control4 */
+#define MVPP22_XLG_CTRL4_REG 0x184
+#define MVPP22_XLG_FORWARD_802_3X_FC_EN BIT(5)
+#define MVPP22_XLG_FORWARD_PFC_EN BIT(6)
+#define MVPP22_XLG_MODE_DMA_1G BIT(12)
+#define MVPP22_XLG_EN_IDLE_CHECK_FOR_LINK BIT(14)
+
+/* XPCS registers */
+
+/* Global Configuration 0 */
+#define MVPP22_XPCS_GLOBAL_CFG_0_REG 0x0
+#define MVPP22_XPCS_PCSRESET BIT(0)
+#define MVPP22_XPCS_PCSMODE_OFFS 3
+#define MVPP22_XPCS_PCSMODE_MASK (0x3 << \
+ MVPP22_XPCS_PCSMODE_OFFS)
+#define MVPP22_XPCS_LANEACTIVE_OFFS 5
+#define MVPP22_XPCS_LANEACTIVE_MASK (0x3 << \
+ MVPP22_XPCS_LANEACTIVE_OFFS)
+
+/* MPCS registers */
+
+#define PCS40G_COMMON_CONTROL 0x14
+#define FORWARD_ERROR_CORRECTION_MASK BIT(10)
+
+#define PCS_CLOCK_RESET 0x14c
+#define TX_SD_CLK_RESET_MASK BIT(0)
+#define RX_SD_CLK_RESET_MASK BIT(1)
+#define MAC_CLK_RESET_MASK BIT(2)
+#define CLK_DIVISION_RATIO_OFFS 4
+#define CLK_DIVISION_RATIO_MASK (0x7 << CLK_DIVISION_RATIO_OFFS)
+#define CLK_DIV_PHASE_SET_MASK BIT(11)
+
+/* System Soft Reset 1 */
+#define GOP_SOFT_RESET_1_REG 0x108
+#define NETC_GOP_SOFT_RESET_OFFS 6
+#define NETC_GOP_SOFT_RESET_MASK (0x1 << \
+ NETC_GOP_SOFT_RESET_OFFS)
+
+/* Ports Control 0 */
+#define NETCOMP_PORTS_CONTROL_0_REG 0x110
+#define NETC_BUS_WIDTH_SELECT_OFFS 1
+#define NETC_BUS_WIDTH_SELECT_MASK (0x1 << \
+ NETC_BUS_WIDTH_SELECT_OFFS)
+#define NETC_GIG_RX_DATA_SAMPLE_OFFS 29
+#define NETC_GIG_RX_DATA_SAMPLE_MASK (0x1 << \
+ NETC_GIG_RX_DATA_SAMPLE_OFFS)
+#define NETC_CLK_DIV_PHASE_OFFS 31
+#define NETC_CLK_DIV_PHASE_MASK (0x1 << NETC_CLK_DIV_PHASE_OFFS)
+/* Ports Control 1 */
+#define NETCOMP_PORTS_CONTROL_1_REG 0x114
+#define NETC_PORTS_ACTIVE_OFFSET(p) (0 + p)
+#define NETC_PORTS_ACTIVE_MASK(p) (0x1 << \
+ NETC_PORTS_ACTIVE_OFFSET(p))
+#define NETC_PORT_GIG_RF_RESET_OFFS(p) (28 + p)
+#define NETC_PORT_GIG_RF_RESET_MASK(p) (0x1 << \
+ NETC_PORT_GIG_RF_RESET_OFFS(p))
+#define NETCOMP_CONTROL_0_REG 0x120
+#define NETC_GBE_PORT0_SGMII_MODE_OFFS 0
+#define NETC_GBE_PORT0_SGMII_MODE_MASK (0x1 << \
+ NETC_GBE_PORT0_SGMII_MODE_OFFS)
+#define NETC_GBE_PORT1_SGMII_MODE_OFFS 1
+#define NETC_GBE_PORT1_SGMII_MODE_MASK (0x1 << \
+ NETC_GBE_PORT1_SGMII_MODE_OFFS)
+#define NETC_GBE_PORT1_MII_MODE_OFFS 2
+#define NETC_GBE_PORT1_MII_MODE_MASK (0x1 << \
+ NETC_GBE_PORT1_MII_MODE_OFFS)
+
+#define MVPP22_SMI_MISC_CFG_REG (MVPP22_SMI + 0x04)
+#define MVPP22_SMI_POLLING_EN BIT(10)
+
+#define MVPP22_SMI_PHY_ADDR_REG(port) (MVPP22_SMI + 0x04 + \
+ (0x4 * (port)))
#define MVPP2_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff
(((index) < (q)->last_desc) ? ((index) + 1) : 0)
/* SMI: 0xc0054 -> offset 0x54 to lms_base */
-#define MVPP2_SMI 0x0054
+#define MVPP21_SMI 0x0054
+/* PP2.2: SMI: 0x12a200 -> offset 0x1200 to iface_base */
+#define MVPP22_SMI 0x1200
#define MVPP2_PHY_REG_MASK 0x1f
/* SMI register fields */
#define MVPP2_SMI_DATA_OFFS 0 /* Data */
#define MVPP2_PHY_ADDR_MASK 0x1f
#define MVPP2_PHY_REG_MASK 0x1f
+/* Additional PPv2.2 offsets */
+#define MVPP22_MPCS 0x007000
+#define MVPP22_XPCS 0x007400
+#define MVPP22_PORT_BASE 0x007e00
+#define MVPP22_PORT_OFFSET 0x001000
+#define MVPP22_RFU1 0x318000
+
+/* Maximum number of ports */
+#define MVPP22_GOP_MAC_NUM 4
+
+/* Sets the field located at the specified in data */
+#define MVPP2_RGMII_TX_FIFO_MIN_TH 0x41
+#define MVPP2_SGMII_TX_FIFO_MIN_TH 0x5
+#define MVPP2_SGMII2_5_TX_FIFO_MIN_TH 0xb
+
+/* Net Complex */
+enum mv_netc_topology {
+ MV_NETC_GE_MAC2_SGMII = BIT(0),
+ MV_NETC_GE_MAC3_SGMII = BIT(1),
+ MV_NETC_GE_MAC3_RGMII = BIT(2),
+};
+
+enum mv_netc_phase {
+ MV_NETC_FIRST_PHASE,
+ MV_NETC_SECOND_PHASE,
+};
+
+enum mv_netc_sgmii_xmi_mode {
+ MV_NETC_GBE_SGMII,
+ MV_NETC_GBE_XMII,
+};
+
+enum mv_netc_mii_mode {
+ MV_NETC_GBE_RGMII,
+ MV_NETC_GBE_MII,
+};
+
+enum mv_netc_lanes {
+ MV_NETC_LANE_23,
+ MV_NETC_LANE_45,
+};
+
/* Various constants */
/* Coalescing */
/* Maximum number of TXQs used by single port */
#define MVPP2_MAX_TXQ 8
-/* Maximum number of RXQs used by single port */
-#define MVPP2_MAX_RXQ 8
-
/* Default number of TXQs in use */
#define MVPP2_DEFAULT_TXQ 1
#define MVPP2_DEFAULT_RXQ 1
#define CONFIG_MV_ETH_RXQ 8 /* increment by 8 */
-/* Total number of RXQs available to all ports */
-#define MVPP2_RXQ_TOTAL_NUM (MVPP2_MAX_PORTS * MVPP2_MAX_RXQ)
-
/* Max number of Rx descriptors */
#define MVPP2_MAX_RXD 16
#define MVPP2_MAX_TXD 16
/* Amount of Tx descriptors that can be reserved at once by CPU */
-#define MVPP2_CPU_DESC_CHUNK 64
+#define MVPP2_CPU_DESC_CHUNK 16
/* Max number of Tx descriptors in each aggregated queue */
-#define MVPP2_AGGR_TXQ_SIZE 256
+#define MVPP2_AGGR_TXQ_SIZE 16
/* Descriptor aligned size */
#define MVPP2_DESC_ALIGNED_SIZE 32
#define MVPP2_TX_DESC_ALIGN (MVPP2_DESC_ALIGNED_SIZE - 1)
/* RX FIFO constants */
-#define MVPP2_RX_FIFO_PORT_DATA_SIZE 0x2000
-#define MVPP2_RX_FIFO_PORT_ATTR_SIZE 0x80
-#define MVPP2_RX_FIFO_PORT_MIN_PKT 0x80
+#define MVPP21_RX_FIFO_PORT_DATA_SIZE 0x2000
+#define MVPP21_RX_FIFO_PORT_ATTR_SIZE 0x80
+#define MVPP22_RX_FIFO_10GB_PORT_DATA_SIZE 0x8000
+#define MVPP22_RX_FIFO_2_5GB_PORT_DATA_SIZE 0x2000
+#define MVPP22_RX_FIFO_1GB_PORT_DATA_SIZE 0x1000
+#define MVPP22_RX_FIFO_10GB_PORT_ATTR_SIZE 0x200
+#define MVPP22_RX_FIFO_2_5GB_PORT_ATTR_SIZE 0x80
+#define MVPP22_RX_FIFO_1GB_PORT_ATTR_SIZE 0x40
+#define MVPP2_RX_FIFO_PORT_MIN_PKT 0x80
+
+/* TX general registers */
+#define MVPP22_TX_FIFO_SIZE_REG(eth_tx_port) (0x8860 + ((eth_tx_port) << 2))
+#define MVPP22_TX_FIFO_SIZE_MASK 0xf
+
+/* TX FIFO constants */
+#define MVPP2_TX_FIFO_DATA_SIZE_10KB 0xa
+#define MVPP2_TX_FIFO_DATA_SIZE_3KB 0x3
/* RX buffer constants */
#define MVPP2_SKB_SHINFO_SIZE \
/* Shared registers' base addresses */
void __iomem *base;
void __iomem *lms_base;
+ void __iomem *iface_base;
+
+ void __iomem *mpcs_base;
+ void __iomem *xpcs_base;
+ void __iomem *rfu1_base;
+
+ u32 netc_config;
/* List of pointers to port structures */
struct mvpp2_port **port_list;
/* HW version */
enum { MVPP21, MVPP22 } hw_version;
- struct mii_dev *bus;
+ /* Maximum number of RXQs per port */
+ unsigned int max_port_rxqs;
+
+ int probe_done;
+ u8 num_ports;
};
struct mvpp2_pcpu_stats {
struct mvpp2_port {
u8 id;
+ /* Index of the port from the "group of ports" complex point
+ * of view
+ */
+ int gop_id;
+
int irq;
struct mvpp2 *priv;
/* Per-port registers' base address */
void __iomem *base;
+ void __iomem *mdio_base;
struct mvpp2_rx_queue **rxqs;
struct mvpp2_tx_queue **txqs;
phy_interface_t phy_interface;
int phy_node;
int phyaddr;
+ struct mii_dev *bus;
+#ifdef CONFIG_DM_GPIO
+ struct gpio_desc phy_reset_gpio;
+ struct gpio_desc phy_tx_disable_gpio;
+#endif
int init;
unsigned int link;
unsigned int duplex;
unsigned int speed;
+ unsigned int phy_speed; /* SGMII 1Gbps vs 2.5Gbps */
+
struct mvpp2_bm_pool *pool_long;
struct mvpp2_bm_pool *pool_short;
/* Ports using BM pool */
u32 port_map;
-
- /* Occupied buffers indicator */
- int in_use_thresh;
};
/* Static declaractions */
/* Number of TXQs used by single port */
static int txq_number = MVPP2_DEFAULT_TXQ;
+static int base_id;
+
#define MVPP2_DRIVER_NAME "mvpp2"
#define MVPP2_DRIVER_VERSION "1.0"
{
u32 val;
+ /* Number of buffer pointers must be a multiple of 16, as per
+ * hardware constraints
+ */
+ if (!IS_ALIGNED(size, 16))
+ return -EINVAL;
+
bm_pool->virt_addr = buffer_loc.bm_pool[bm_pool->id];
bm_pool->dma_addr = (dma_addr_t)buffer_loc.bm_pool[bm_pool->id];
if (!bm_pool->virt_addr)
}
mvpp2_write(priv, MVPP2_BM_POOL_BASE_REG(bm_pool->id),
- bm_pool->dma_addr);
+ lower_32_bits(bm_pool->dma_addr));
+ if (priv->hw_version == MVPP22)
+ mvpp2_write(priv, MVPP22_BM_POOL_BASE_HIGH_REG,
+ (upper_32_bits(bm_pool->dma_addr) &
+ MVPP22_BM_POOL_BASE_HIGH_MASK));
mvpp2_write(priv, MVPP2_BM_POOL_SIZE_REG(bm_pool->id), size);
val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id));
static void mvpp2_bm_bufs_free(struct udevice *dev, struct mvpp2 *priv,
struct mvpp2_bm_pool *bm_pool)
{
+ int i;
+
+ for (i = 0; i < bm_pool->buf_num; i++) {
+ /* Allocate buffer back from the buffer manager */
+ mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
+ }
+
bm_pool->buf_num = 0;
}
err = mvpp2_bm_pool_create(dev, priv, bm_pool, size);
if (err)
goto err_unroll_pools;
- mvpp2_bm_pool_bufsize_set(priv, bm_pool, 0);
+ mvpp2_bm_pool_bufsize_set(priv, bm_pool, RX_BUFFER_SIZE);
}
return 0;
static void mvpp2_rxq_long_pool_set(struct mvpp2_port *port,
int lrxq, int long_pool)
{
- u32 val;
+ u32 val, mask;
int prxq;
/* Get queue physical ID */
prxq = port->rxqs[lrxq]->id;
- val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
- val &= ~MVPP2_RXQ_POOL_LONG_MASK;
- val |= ((long_pool << MVPP2_RXQ_POOL_LONG_OFFS) &
- MVPP2_RXQ_POOL_LONG_MASK);
+ if (port->priv->hw_version == MVPP21)
+ mask = MVPP21_RXQ_POOL_LONG_MASK;
+ else
+ mask = MVPP22_RXQ_POOL_LONG_MASK;
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
+ val &= ~mask;
+ val |= (long_pool << MVPP2_RXQ_POOL_LONG_OFFS) & mask;
mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val);
}
dma_addr_t buf_dma_addr,
unsigned long buf_phys_addr)
{
+ if (port->priv->hw_version == MVPP22) {
+ u32 val = 0;
+
+ if (sizeof(dma_addr_t) == 8)
+ val |= upper_32_bits(buf_dma_addr) &
+ MVPP22_BM_ADDR_HIGH_PHYS_RLS_MASK;
+
+ if (sizeof(phys_addr_t) == 8)
+ val |= (upper_32_bits(buf_phys_addr)
+ << MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) &
+ MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK;
+
+ mvpp2_write(port->priv, MVPP22_BM_ADDR_HIGH_RLS_REG, val);
+ }
+
/* MVPP2_BM_VIRT_RLS_REG is not interpreted by HW, and simply
* returned in the "cookie" field of the RX
* descriptor. Instead of storing the virtual address, we
/* Update BM driver with number of buffers added to pool */
bm_pool->buf_num += i;
- bm_pool->in_use_thresh = bm_pool->buf_num / 4;
return i;
}
}
}
- mvpp2_bm_pool_bufsize_set(port->priv, new_pool,
- MVPP2_RX_BUF_SIZE(new_pool->pkt_size));
-
return new_pool;
}
val |= MVPP2_GMAC_INBAND_AN_MASK;
break;
case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
val |= MVPP2_GMAC_PORT_RGMII_MASK;
default:
val &= ~MVPP2_GMAC_PCS_ENABLE_MASK;
writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
}
-/* Set defaults to the MVPP2 port */
-static void mvpp2_defaults_set(struct mvpp2_port *port)
-{
- int tx_port_num, val, queue, ptxq, lrxq;
-
- /* Configure port to loopback if needed */
- if (port->flags & MVPP2_F_LOOPBACK)
- mvpp2_port_loopback_set(port);
-
- /* Update TX FIFO MIN Threshold */
- val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
- val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK;
- /* Min. TX threshold must be less than minimal packet length */
- val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(64 - 4 - 2);
- writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
-
- /* Disable Legacy WRR, Disable EJP, Release from reset */
- tx_port_num = mvpp2_egress_port(port);
- mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG,
- tx_port_num);
- mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0);
-
- /* Close bandwidth for all queues */
- for (queue = 0; queue < MVPP2_MAX_TXQ; queue++) {
- ptxq = mvpp2_txq_phys(port->id, queue);
- mvpp2_write(port->priv,
- MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(ptxq), 0);
- }
+/* PPv2.2 GoP/GMAC config */
- /* Set refill period to 1 usec, refill tokens
- * and bucket size to maximum
- */
- mvpp2_write(port->priv, MVPP2_TXP_SCHED_PERIOD_REG, 0xc8);
- val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_REFILL_REG);
- val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK;
- val |= MVPP2_TXP_REFILL_PERIOD_MASK(1);
- val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK;
- mvpp2_write(port->priv, MVPP2_TXP_SCHED_REFILL_REG, val);
- val = MVPP2_TXP_TOKEN_SIZE_MAX;
- mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val);
+/* Set the MAC to reset or exit from reset */
+static int gop_gmac_reset(struct mvpp2_port *port, int reset)
+{
+ u32 val;
- /* Set MaximumLowLatencyPacketSize value to 256 */
- mvpp2_write(port->priv, MVPP2_RX_CTRL_REG(port->id),
- MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK |
- MVPP2_RX_LOW_LATENCY_PKT_SIZE(256));
+ /* read - modify - write */
+ val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
+ if (reset)
+ val |= MVPP2_GMAC_PORT_RESET_MASK;
+ else
+ val &= ~MVPP2_GMAC_PORT_RESET_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
- /* Enable Rx cache snoop */
- for (lrxq = 0; lrxq < rxq_number; lrxq++) {
- queue = port->rxqs[lrxq]->id;
- val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
- val |= MVPP2_SNOOP_PKT_SIZE_MASK |
- MVPP2_SNOOP_BUF_HDR_MASK;
- mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val);
- }
+ return 0;
}
-/* Enable/disable receiving packets */
-static void mvpp2_ingress_enable(struct mvpp2_port *port)
+/*
+ * gop_gpcs_mode_cfg
+ *
+ * Configure port to working with Gig PCS or don't.
+ */
+static int gop_gpcs_mode_cfg(struct mvpp2_port *port, int en)
{
u32 val;
- int lrxq, queue;
- for (lrxq = 0; lrxq < rxq_number; lrxq++) {
- queue = port->rxqs[lrxq]->id;
- val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
- val &= ~MVPP2_RXQ_DISABLE_MASK;
- mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val);
- }
+ val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
+ if (en)
+ val |= MVPP2_GMAC_PCS_ENABLE_MASK;
+ else
+ val &= ~MVPP2_GMAC_PCS_ENABLE_MASK;
+ /* enable / disable PCS on this port */
+ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
+
+ return 0;
}
-static void mvpp2_ingress_disable(struct mvpp2_port *port)
+static int gop_bypass_clk_cfg(struct mvpp2_port *port, int en)
{
u32 val;
- int lrxq, queue;
- for (lrxq = 0; lrxq < rxq_number; lrxq++) {
- queue = port->rxqs[lrxq]->id;
- val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
- val |= MVPP2_RXQ_DISABLE_MASK;
- mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val);
- }
+ val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
+ if (en)
+ val |= MVPP2_GMAC_CLK_125_BYPS_EN_MASK;
+ else
+ val &= ~MVPP2_GMAC_CLK_125_BYPS_EN_MASK;
+ /* enable / disable PCS on this port */
+ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
+
+ return 0;
}
-/* Enable transmit via physical egress queue
- * - HW starts take descriptors from DRAM
- */
-static void mvpp2_egress_enable(struct mvpp2_port *port)
+static void gop_gmac_sgmii2_5_cfg(struct mvpp2_port *port)
{
- u32 qmap;
- int queue;
- int tx_port_num = mvpp2_egress_port(port);
+ u32 val, thresh;
- /* Enable all initialized TXs. */
- qmap = 0;
- for (queue = 0; queue < txq_number; queue++) {
- struct mvpp2_tx_queue *txq = port->txqs[queue];
+ /*
+ * Configure minimal level of the Tx FIFO before the lower part
+ * starts to read a packet
+ */
+ thresh = MVPP2_SGMII2_5_TX_FIFO_MIN_TH;
+ val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
+ val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK;
+ val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(thresh);
+ writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
- if (txq->descs != NULL)
- qmap |= (1 << queue);
- }
+ /* Disable bypass of sync module */
+ val = readl(port->base + MVPP2_GMAC_CTRL_4_REG);
+ val |= MVPP2_GMAC_CTRL4_SYNC_BYPASS_MASK;
+ /* configure DP clock select according to mode */
+ val |= MVPP2_GMAC_CTRL4_DP_CLK_SEL_MASK;
+ /* configure QSGMII bypass according to mode */
+ val |= MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_4_REG);
- mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num);
- mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG, qmap);
+ val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
+ /*
+ * Configure GIG MAC to 1000Base-X mode connected to a fiber
+ * transceiver
+ */
+ val |= MVPP2_GMAC_PORT_TYPE_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
+
+ /* configure AN 0x9268 */
+ val = MVPP2_GMAC_EN_PCS_AN |
+ MVPP2_GMAC_AN_BYPASS_EN |
+ MVPP2_GMAC_CONFIG_MII_SPEED |
+ MVPP2_GMAC_CONFIG_GMII_SPEED |
+ MVPP2_GMAC_FC_ADV_EN |
+ MVPP2_GMAC_CONFIG_FULL_DUPLEX |
+ MVPP2_GMAC_CHOOSE_SAMPLE_TX_CONFIG;
+ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
}
-/* Disable transmit via physical egress queue
- * - HW doesn't take descriptors from DRAM
- */
-static void mvpp2_egress_disable(struct mvpp2_port *port)
+static void gop_gmac_sgmii_cfg(struct mvpp2_port *port)
{
- u32 reg_data;
- int delay;
- int tx_port_num = mvpp2_egress_port(port);
-
- /* Issue stop command for active channels only */
- mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num);
- reg_data = (mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG)) &
- MVPP2_TXP_SCHED_ENQ_MASK;
- if (reg_data != 0)
- mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG,
- (reg_data << MVPP2_TXP_SCHED_DISQ_OFFSET));
-
- /* Wait for all Tx activity to terminate. */
- delay = 0;
- do {
- if (delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) {
- netdev_warn(port->dev,
- "Tx stop timed out, status=0x%08x\n",
- reg_data);
- break;
- }
- mdelay(1);
- delay++;
+ u32 val, thresh;
- /* Check port TX Command register that all
- * Tx queues are stopped
- */
- reg_data = mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG);
- } while (reg_data & MVPP2_TXP_SCHED_ENQ_MASK);
-}
+ /*
+ * Configure minimal level of the Tx FIFO before the lower part
+ * starts to read a packet
+ */
+ thresh = MVPP2_SGMII_TX_FIFO_MIN_TH;
+ val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
+ val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK;
+ val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(thresh);
+ writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
-/* Rx descriptors helper methods */
+ /* Disable bypass of sync module */
+ val = readl(port->base + MVPP2_GMAC_CTRL_4_REG);
+ val |= MVPP2_GMAC_CTRL4_SYNC_BYPASS_MASK;
+ /* configure DP clock select according to mode */
+ val &= ~MVPP2_GMAC_CTRL4_DP_CLK_SEL_MASK;
+ /* configure QSGMII bypass according to mode */
+ val |= MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_4_REG);
-/* Get number of Rx descriptors occupied by received packets */
-static inline int
-mvpp2_rxq_received(struct mvpp2_port *port, int rxq_id)
-{
- u32 val = mvpp2_read(port->priv, MVPP2_RXQ_STATUS_REG(rxq_id));
+ val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
+ /* configure GIG MAC to SGMII mode */
+ val &= ~MVPP2_GMAC_PORT_TYPE_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
- return val & MVPP2_RXQ_OCCUPIED_MASK;
+ /* configure AN */
+ val = MVPP2_GMAC_EN_PCS_AN |
+ MVPP2_GMAC_AN_BYPASS_EN |
+ MVPP2_GMAC_AN_SPEED_EN |
+ MVPP2_GMAC_EN_FC_AN |
+ MVPP2_GMAC_AN_DUPLEX_EN |
+ MVPP2_GMAC_CHOOSE_SAMPLE_TX_CONFIG;
+ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
}
-/* Update Rx queue status with the number of occupied and available
- * Rx descriptor slots.
- */
-static inline void
-mvpp2_rxq_status_update(struct mvpp2_port *port, int rxq_id,
- int used_count, int free_count)
+static void gop_gmac_rgmii_cfg(struct mvpp2_port *port)
{
- /* Decrement the number of used descriptors and increment count
- * increment the number of free descriptors.
+ u32 val, thresh;
+
+ /*
+ * Configure minimal level of the Tx FIFO before the lower part
+ * starts to read a packet
*/
- u32 val = used_count | (free_count << MVPP2_RXQ_NUM_NEW_OFFSET);
+ thresh = MVPP2_RGMII_TX_FIFO_MIN_TH;
+ val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
+ val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK;
+ val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(thresh);
+ writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
- mvpp2_write(port->priv, MVPP2_RXQ_STATUS_UPDATE_REG(rxq_id), val);
-}
+ /* Disable bypass of sync module */
+ val = readl(port->base + MVPP2_GMAC_CTRL_4_REG);
+ val |= MVPP2_GMAC_CTRL4_SYNC_BYPASS_MASK;
+ /* configure DP clock select according to mode */
+ val &= ~MVPP2_GMAC_CTRL4_DP_CLK_SEL_MASK;
+ val |= MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
+ val |= MVPP2_GMAC_CTRL4_EXT_PIN_GMII_SEL_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_4_REG);
-/* Get pointer to next RX descriptor to be processed by SW */
-static inline struct mvpp2_rx_desc *
-mvpp2_rxq_next_desc_get(struct mvpp2_rx_queue *rxq)
-{
- int rx_desc = rxq->next_desc_to_proc;
+ val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
+ /* configure GIG MAC to SGMII mode */
+ val &= ~MVPP2_GMAC_PORT_TYPE_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
- rxq->next_desc_to_proc = MVPP2_QUEUE_NEXT_DESC(rxq, rx_desc);
- prefetch(rxq->descs + rxq->next_desc_to_proc);
- return rxq->descs + rx_desc;
+ /* configure AN 0xb8e8 */
+ val = MVPP2_GMAC_AN_BYPASS_EN |
+ MVPP2_GMAC_AN_SPEED_EN |
+ MVPP2_GMAC_EN_FC_AN |
+ MVPP2_GMAC_AN_DUPLEX_EN |
+ MVPP2_GMAC_CHOOSE_SAMPLE_TX_CONFIG;
+ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
}
-/* Set rx queue offset */
-static void mvpp2_rxq_offset_set(struct mvpp2_port *port,
- int prxq, int offset)
+/* Set the internal mux's to the required MAC in the GOP */
+static int gop_gmac_mode_cfg(struct mvpp2_port *port)
{
u32 val;
- /* Convert offset from bytes to units of 32 bytes */
- offset = offset >> 5;
+ /* Set TX FIFO thresholds */
+ switch (port->phy_interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ if (port->phy_speed == 2500)
+ gop_gmac_sgmii2_5_cfg(port);
+ else
+ gop_gmac_sgmii_cfg(port);
+ break;
- val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
- val &= ~MVPP2_RXQ_PACKET_OFFSET_MASK;
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ gop_gmac_rgmii_cfg(port);
+ break;
- /* Offset is in */
- val |= ((offset << MVPP2_RXQ_PACKET_OFFSET_OFFS) &
- MVPP2_RXQ_PACKET_OFFSET_MASK);
+ default:
+ return -1;
+ }
+
+ /* Jumbo frame support - 0x1400*2= 0x2800 bytes */
+ val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
+ val &= ~MVPP2_GMAC_MAX_RX_SIZE_MASK;
+ val |= 0x1400 << MVPP2_GMAC_MAX_RX_SIZE_OFFS;
+ writel(val, port->base + MVPP2_GMAC_CTRL_0_REG);
+
+ /* PeriodicXonEn disable */
+ val = readl(port->base + MVPP2_GMAC_CTRL_1_REG);
+ val &= ~MVPP2_GMAC_PERIODIC_XON_EN_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_1_REG);
+
+ return 0;
+}
+
+static void gop_xlg_2_gig_mac_cfg(struct mvpp2_port *port)
+{
+ u32 val;
+
+ /* relevant only for MAC0 (XLG0 and GMAC0) */
+ if (port->gop_id > 0)
+ return;
+
+ /* configure 1Gig MAC mode */
+ val = readl(port->base + MVPP22_XLG_CTRL3_REG);
+ val &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
+ val |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC;
+ writel(val, port->base + MVPP22_XLG_CTRL3_REG);
+}
+
+static int gop_gpcs_reset(struct mvpp2_port *port, int reset)
+{
+ u32 val;
+
+ val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
+ if (reset)
+ val &= ~MVPP2_GMAC_SGMII_MODE_MASK;
+ else
+ val |= MVPP2_GMAC_SGMII_MODE_MASK;
+ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
+
+ return 0;
+}
+
+/* Set the internal mux's to the required PCS in the PI */
+static int gop_xpcs_mode(struct mvpp2_port *port, int num_of_lanes)
+{
+ u32 val;
+ int lane;
+
+ switch (num_of_lanes) {
+ case 1:
+ lane = 0;
+ break;
+ case 2:
+ lane = 1;
+ break;
+ case 4:
+ lane = 2;
+ break;
+ default:
+ return -1;
+ }
+
+ /* configure XG MAC mode */
+ val = readl(port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG);
+ val &= ~MVPP22_XPCS_PCSMODE_MASK;
+ val &= ~MVPP22_XPCS_LANEACTIVE_MASK;
+ val |= (2 * lane) << MVPP22_XPCS_LANEACTIVE_OFFS;
+ writel(val, port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG);
+
+ return 0;
+}
+
+static int gop_mpcs_mode(struct mvpp2_port *port)
+{
+ u32 val;
+
+ /* configure PCS40G COMMON CONTROL */
+ val = readl(port->priv->mpcs_base + PCS40G_COMMON_CONTROL);
+ val &= ~FORWARD_ERROR_CORRECTION_MASK;
+ writel(val, port->priv->mpcs_base + PCS40G_COMMON_CONTROL);
+
+ /* configure PCS CLOCK RESET */
+ val = readl(port->priv->mpcs_base + PCS_CLOCK_RESET);
+ val &= ~CLK_DIVISION_RATIO_MASK;
+ val |= 1 << CLK_DIVISION_RATIO_OFFS;
+ writel(val, port->priv->mpcs_base + PCS_CLOCK_RESET);
+
+ val &= ~CLK_DIV_PHASE_SET_MASK;
+ val |= MAC_CLK_RESET_MASK;
+ val |= RX_SD_CLK_RESET_MASK;
+ val |= TX_SD_CLK_RESET_MASK;
+ writel(val, port->priv->mpcs_base + PCS_CLOCK_RESET);
+
+ return 0;
+}
+
+/* Set the internal mux's to the required MAC in the GOP */
+static int gop_xlg_mac_mode_cfg(struct mvpp2_port *port, int num_of_act_lanes)
+{
+ u32 val;
+
+ /* configure 10G MAC mode */
+ val = readl(port->base + MVPP22_XLG_CTRL0_REG);
+ val |= MVPP22_XLG_RX_FC_EN;
+ writel(val, port->base + MVPP22_XLG_CTRL0_REG);
+
+ val = readl(port->base + MVPP22_XLG_CTRL3_REG);
+ val &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
+ val |= MVPP22_XLG_CTRL3_MACMODESELECT_10GMAC;
+ writel(val, port->base + MVPP22_XLG_CTRL3_REG);
+
+ /* read - modify - write */
+ val = readl(port->base + MVPP22_XLG_CTRL4_REG);
+ val &= ~MVPP22_XLG_MODE_DMA_1G;
+ val |= MVPP22_XLG_FORWARD_PFC_EN;
+ val |= MVPP22_XLG_FORWARD_802_3X_FC_EN;
+ val &= ~MVPP22_XLG_EN_IDLE_CHECK_FOR_LINK;
+ writel(val, port->base + MVPP22_XLG_CTRL4_REG);
+
+ /* Jumbo frame support: 0x1400 * 2 = 0x2800 bytes */
+ val = readl(port->base + MVPP22_XLG_CTRL1_REG);
+ val &= ~MVPP22_XLG_MAX_RX_SIZE_MASK;
+ val |= 0x1400 << MVPP22_XLG_MAX_RX_SIZE_OFFS;
+ writel(val, port->base + MVPP22_XLG_CTRL1_REG);
+
+ /* unmask link change interrupt */
+ val = readl(port->base + MVPP22_XLG_INTERRUPT_MASK_REG);
+ val |= MVPP22_XLG_INTERRUPT_LINK_CHANGE;
+ val |= 1; /* unmask summary bit */
+ writel(val, port->base + MVPP22_XLG_INTERRUPT_MASK_REG);
+
+ return 0;
+}
+
+/* Set PCS to reset or exit from reset */
+static int gop_xpcs_reset(struct mvpp2_port *port, int reset)
+{
+ u32 val;
+
+ /* read - modify - write */
+ val = readl(port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG);
+ if (reset)
+ val &= ~MVPP22_XPCS_PCSRESET;
+ else
+ val |= MVPP22_XPCS_PCSRESET;
+ writel(val, port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG);
+
+ return 0;
+}
+
+/* Set the MAC to reset or exit from reset */
+static int gop_xlg_mac_reset(struct mvpp2_port *port, int reset)
+{
+ u32 val;
+
+ /* read - modify - write */
+ val = readl(port->base + MVPP22_XLG_CTRL0_REG);
+ if (reset)
+ val &= ~MVPP22_XLG_MAC_RESETN;
+ else
+ val |= MVPP22_XLG_MAC_RESETN;
+ writel(val, port->base + MVPP22_XLG_CTRL0_REG);
+
+ return 0;
+}
+
+/*
+ * gop_port_init
+ *
+ * Init physical port. Configures the port mode and all it's elements
+ * accordingly.
+ * Does not verify that the selected mode/port number is valid at the
+ * core level.
+ */
+static int gop_port_init(struct mvpp2_port *port)
+{
+ int mac_num = port->gop_id;
+ int num_of_act_lanes;
+
+ if (mac_num >= MVPP22_GOP_MAC_NUM) {
+ netdev_err(NULL, "%s: illegal port number %d", __func__,
+ mac_num);
+ return -1;
+ }
+
+ switch (port->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ gop_gmac_reset(port, 1);
+
+ /* configure PCS */
+ gop_gpcs_mode_cfg(port, 0);
+ gop_bypass_clk_cfg(port, 1);
+
+ /* configure MAC */
+ gop_gmac_mode_cfg(port);
+ /* pcs unreset */
+ gop_gpcs_reset(port, 0);
+
+ /* mac unreset */
+ gop_gmac_reset(port, 0);
+ break;
+
+ case PHY_INTERFACE_MODE_SGMII:
+ /* configure PCS */
+ gop_gpcs_mode_cfg(port, 1);
+
+ /* configure MAC */
+ gop_gmac_mode_cfg(port);
+ /* select proper Mac mode */
+ gop_xlg_2_gig_mac_cfg(port);
+
+ /* pcs unreset */
+ gop_gpcs_reset(port, 0);
+ /* mac unreset */
+ gop_gmac_reset(port, 0);
+ break;
+
+ case PHY_INTERFACE_MODE_SFI:
+ num_of_act_lanes = 2;
+ mac_num = 0;
+ /* configure PCS */
+ gop_xpcs_mode(port, num_of_act_lanes);
+ gop_mpcs_mode(port);
+ /* configure MAC */
+ gop_xlg_mac_mode_cfg(port, num_of_act_lanes);
+
+ /* pcs unreset */
+ gop_xpcs_reset(port, 0);
+
+ /* mac unreset */
+ gop_xlg_mac_reset(port, 0);
+ break;
+
+ default:
+ netdev_err(NULL, "%s: Requested port mode (%d) not supported\n",
+ __func__, port->phy_interface);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void gop_xlg_mac_port_enable(struct mvpp2_port *port, int enable)
+{
+ u32 val;
+
+ val = readl(port->base + MVPP22_XLG_CTRL0_REG);
+ if (enable) {
+ /* Enable port and MIB counters update */
+ val |= MVPP22_XLG_PORT_EN;
+ val &= ~MVPP22_XLG_MIBCNT_DIS;
+ } else {
+ /* Disable port */
+ val &= ~MVPP22_XLG_PORT_EN;
+ }
+ writel(val, port->base + MVPP22_XLG_CTRL0_REG);
+}
+
+static void gop_port_enable(struct mvpp2_port *port, int enable)
+{
+ switch (port->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_SGMII:
+ if (enable)
+ mvpp2_port_enable(port);
+ else
+ mvpp2_port_disable(port);
+ break;
+
+ case PHY_INTERFACE_MODE_SFI:
+ gop_xlg_mac_port_enable(port, enable);
+
+ break;
+ default:
+ netdev_err(NULL, "%s: Wrong port mode (%d)\n", __func__,
+ port->phy_interface);
+ return;
+ }
+}
+
+/* RFU1 functions */
+static inline u32 gop_rfu1_read(struct mvpp2 *priv, u32 offset)
+{
+ return readl(priv->rfu1_base + offset);
+}
+
+static inline void gop_rfu1_write(struct mvpp2 *priv, u32 offset, u32 data)
+{
+ writel(data, priv->rfu1_base + offset);
+}
+
+static u32 mvpp2_netc_cfg_create(int gop_id, phy_interface_t phy_type)
+{
+ u32 val = 0;
+
+ if (gop_id == 2) {
+ if (phy_type == PHY_INTERFACE_MODE_SGMII)
+ val |= MV_NETC_GE_MAC2_SGMII;
+ }
+
+ if (gop_id == 3) {
+ if (phy_type == PHY_INTERFACE_MODE_SGMII)
+ val |= MV_NETC_GE_MAC3_SGMII;
+ else if (phy_type == PHY_INTERFACE_MODE_RGMII ||
+ phy_type == PHY_INTERFACE_MODE_RGMII_ID)
+ val |= MV_NETC_GE_MAC3_RGMII;
+ }
+
+ return val;
+}
+
+static void gop_netc_active_port(struct mvpp2 *priv, int gop_id, u32 val)
+{
+ u32 reg;
+
+ reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_1_REG);
+ reg &= ~(NETC_PORTS_ACTIVE_MASK(gop_id));
+
+ val <<= NETC_PORTS_ACTIVE_OFFSET(gop_id);
+ val &= NETC_PORTS_ACTIVE_MASK(gop_id);
+
+ reg |= val;
+
+ gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_1_REG, reg);
+}
+
+static void gop_netc_mii_mode(struct mvpp2 *priv, int gop_id, u32 val)
+{
+ u32 reg;
+
+ reg = gop_rfu1_read(priv, NETCOMP_CONTROL_0_REG);
+ reg &= ~NETC_GBE_PORT1_MII_MODE_MASK;
+
+ val <<= NETC_GBE_PORT1_MII_MODE_OFFS;
+ val &= NETC_GBE_PORT1_MII_MODE_MASK;
+
+ reg |= val;
+
+ gop_rfu1_write(priv, NETCOMP_CONTROL_0_REG, reg);
+}
+
+static void gop_netc_gop_reset(struct mvpp2 *priv, u32 val)
+{
+ u32 reg;
+
+ reg = gop_rfu1_read(priv, GOP_SOFT_RESET_1_REG);
+ reg &= ~NETC_GOP_SOFT_RESET_MASK;
+
+ val <<= NETC_GOP_SOFT_RESET_OFFS;
+ val &= NETC_GOP_SOFT_RESET_MASK;
+
+ reg |= val;
+
+ gop_rfu1_write(priv, GOP_SOFT_RESET_1_REG, reg);
+}
+
+static void gop_netc_gop_clock_logic_set(struct mvpp2 *priv, u32 val)
+{
+ u32 reg;
+
+ reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_0_REG);
+ reg &= ~NETC_CLK_DIV_PHASE_MASK;
+
+ val <<= NETC_CLK_DIV_PHASE_OFFS;
+ val &= NETC_CLK_DIV_PHASE_MASK;
+
+ reg |= val;
+
+ gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_0_REG, reg);
+}
+
+static void gop_netc_port_rf_reset(struct mvpp2 *priv, int gop_id, u32 val)
+{
+ u32 reg;
+
+ reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_1_REG);
+ reg &= ~(NETC_PORT_GIG_RF_RESET_MASK(gop_id));
+
+ val <<= NETC_PORT_GIG_RF_RESET_OFFS(gop_id);
+ val &= NETC_PORT_GIG_RF_RESET_MASK(gop_id);
+
+ reg |= val;
+
+ gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_1_REG, reg);
+}
+
+static void gop_netc_gbe_sgmii_mode_select(struct mvpp2 *priv, int gop_id,
+ u32 val)
+{
+ u32 reg, mask, offset;
+
+ if (gop_id == 2) {
+ mask = NETC_GBE_PORT0_SGMII_MODE_MASK;
+ offset = NETC_GBE_PORT0_SGMII_MODE_OFFS;
+ } else {
+ mask = NETC_GBE_PORT1_SGMII_MODE_MASK;
+ offset = NETC_GBE_PORT1_SGMII_MODE_OFFS;
+ }
+ reg = gop_rfu1_read(priv, NETCOMP_CONTROL_0_REG);
+ reg &= ~mask;
+
+ val <<= offset;
+ val &= mask;
+
+ reg |= val;
+
+ gop_rfu1_write(priv, NETCOMP_CONTROL_0_REG, reg);
+}
+
+static void gop_netc_bus_width_select(struct mvpp2 *priv, u32 val)
+{
+ u32 reg;
+
+ reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_0_REG);
+ reg &= ~NETC_BUS_WIDTH_SELECT_MASK;
+
+ val <<= NETC_BUS_WIDTH_SELECT_OFFS;
+ val &= NETC_BUS_WIDTH_SELECT_MASK;
+
+ reg |= val;
+
+ gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_0_REG, reg);
+}
+
+static void gop_netc_sample_stages_timing(struct mvpp2 *priv, u32 val)
+{
+ u32 reg;
+
+ reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_0_REG);
+ reg &= ~NETC_GIG_RX_DATA_SAMPLE_MASK;
+
+ val <<= NETC_GIG_RX_DATA_SAMPLE_OFFS;
+ val &= NETC_GIG_RX_DATA_SAMPLE_MASK;
+
+ reg |= val;
+
+ gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_0_REG, reg);
+}
+
+static void gop_netc_mac_to_xgmii(struct mvpp2 *priv, int gop_id,
+ enum mv_netc_phase phase)
+{
+ switch (phase) {
+ case MV_NETC_FIRST_PHASE:
+ /* Set Bus Width to HB mode = 1 */
+ gop_netc_bus_width_select(priv, 1);
+ /* Select RGMII mode */
+ gop_netc_gbe_sgmii_mode_select(priv, gop_id, MV_NETC_GBE_XMII);
+ break;
+
+ case MV_NETC_SECOND_PHASE:
+ /* De-assert the relevant port HB reset */
+ gop_netc_port_rf_reset(priv, gop_id, 1);
+ break;
+ }
+}
+
+static void gop_netc_mac_to_sgmii(struct mvpp2 *priv, int gop_id,
+ enum mv_netc_phase phase)
+{
+ switch (phase) {
+ case MV_NETC_FIRST_PHASE:
+ /* Set Bus Width to HB mode = 1 */
+ gop_netc_bus_width_select(priv, 1);
+ /* Select SGMII mode */
+ if (gop_id >= 1) {
+ gop_netc_gbe_sgmii_mode_select(priv, gop_id,
+ MV_NETC_GBE_SGMII);
+ }
+
+ /* Configure the sample stages */
+ gop_netc_sample_stages_timing(priv, 0);
+ /* Configure the ComPhy Selector */
+ /* gop_netc_com_phy_selector_config(netComplex); */
+ break;
+
+ case MV_NETC_SECOND_PHASE:
+ /* De-assert the relevant port HB reset */
+ gop_netc_port_rf_reset(priv, gop_id, 1);
+ break;
+ }
+}
+
+static int gop_netc_init(struct mvpp2 *priv, enum mv_netc_phase phase)
+{
+ u32 c = priv->netc_config;
+
+ if (c & MV_NETC_GE_MAC2_SGMII)
+ gop_netc_mac_to_sgmii(priv, 2, phase);
+ else
+ gop_netc_mac_to_xgmii(priv, 2, phase);
+
+ if (c & MV_NETC_GE_MAC3_SGMII) {
+ gop_netc_mac_to_sgmii(priv, 3, phase);
+ } else {
+ gop_netc_mac_to_xgmii(priv, 3, phase);
+ if (c & MV_NETC_GE_MAC3_RGMII)
+ gop_netc_mii_mode(priv, 3, MV_NETC_GBE_RGMII);
+ else
+ gop_netc_mii_mode(priv, 3, MV_NETC_GBE_MII);
+ }
+
+ /* Activate gop ports 0, 2, 3 */
+ gop_netc_active_port(priv, 0, 1);
+ gop_netc_active_port(priv, 2, 1);
+ gop_netc_active_port(priv, 3, 1);
+
+ if (phase == MV_NETC_SECOND_PHASE) {
+ /* Enable the GOP internal clock logic */
+ gop_netc_gop_clock_logic_set(priv, 1);
+ /* De-assert GOP unit reset */
+ gop_netc_gop_reset(priv, 1);
+ }
+
+ return 0;
+}
+
+/* Set defaults to the MVPP2 port */
+static void mvpp2_defaults_set(struct mvpp2_port *port)
+{
+ int tx_port_num, val, queue, ptxq, lrxq;
+
+ if (port->priv->hw_version == MVPP21) {
+ /* Configure port to loopback if needed */
+ if (port->flags & MVPP2_F_LOOPBACK)
+ mvpp2_port_loopback_set(port);
+
+ /* Update TX FIFO MIN Threshold */
+ val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
+ val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK;
+ /* Min. TX threshold must be less than minimal packet length */
+ val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(64 - 4 - 2);
+ writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG);
+ }
+
+ /* Disable Legacy WRR, Disable EJP, Release from reset */
+ tx_port_num = mvpp2_egress_port(port);
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG,
+ tx_port_num);
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0);
+
+ /* Close bandwidth for all queues */
+ for (queue = 0; queue < MVPP2_MAX_TXQ; queue++) {
+ ptxq = mvpp2_txq_phys(port->id, queue);
+ mvpp2_write(port->priv,
+ MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(ptxq), 0);
+ }
+
+ /* Set refill period to 1 usec, refill tokens
+ * and bucket size to maximum
+ */
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_PERIOD_REG, 0xc8);
+ val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_REFILL_REG);
+ val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK;
+ val |= MVPP2_TXP_REFILL_PERIOD_MASK(1);
+ val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK;
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_REFILL_REG, val);
+ val = MVPP2_TXP_TOKEN_SIZE_MAX;
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val);
+
+ /* Set MaximumLowLatencyPacketSize value to 256 */
+ mvpp2_write(port->priv, MVPP2_RX_CTRL_REG(port->id),
+ MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK |
+ MVPP2_RX_LOW_LATENCY_PKT_SIZE(256));
+
+ /* Enable Rx cache snoop */
+ for (lrxq = 0; lrxq < rxq_number; lrxq++) {
+ queue = port->rxqs[lrxq]->id;
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
+ val |= MVPP2_SNOOP_PKT_SIZE_MASK |
+ MVPP2_SNOOP_BUF_HDR_MASK;
+ mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val);
+ }
+}
+
+/* Enable/disable receiving packets */
+static void mvpp2_ingress_enable(struct mvpp2_port *port)
+{
+ u32 val;
+ int lrxq, queue;
+
+ for (lrxq = 0; lrxq < rxq_number; lrxq++) {
+ queue = port->rxqs[lrxq]->id;
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
+ val &= ~MVPP2_RXQ_DISABLE_MASK;
+ mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val);
+ }
+}
+
+static void mvpp2_ingress_disable(struct mvpp2_port *port)
+{
+ u32 val;
+ int lrxq, queue;
+
+ for (lrxq = 0; lrxq < rxq_number; lrxq++) {
+ queue = port->rxqs[lrxq]->id;
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue));
+ val |= MVPP2_RXQ_DISABLE_MASK;
+ mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val);
+ }
+}
+
+/* Enable transmit via physical egress queue
+ * - HW starts take descriptors from DRAM
+ */
+static void mvpp2_egress_enable(struct mvpp2_port *port)
+{
+ u32 qmap;
+ int queue;
+ int tx_port_num = mvpp2_egress_port(port);
+
+ /* Enable all initialized TXs. */
+ qmap = 0;
+ for (queue = 0; queue < txq_number; queue++) {
+ struct mvpp2_tx_queue *txq = port->txqs[queue];
+
+ if (txq->descs != NULL)
+ qmap |= (1 << queue);
+ }
+
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num);
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG, qmap);
+}
+
+/* Disable transmit via physical egress queue
+ * - HW doesn't take descriptors from DRAM
+ */
+static void mvpp2_egress_disable(struct mvpp2_port *port)
+{
+ u32 reg_data;
+ int delay;
+ int tx_port_num = mvpp2_egress_port(port);
+
+ /* Issue stop command for active channels only */
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num);
+ reg_data = (mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG)) &
+ MVPP2_TXP_SCHED_ENQ_MASK;
+ if (reg_data != 0)
+ mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG,
+ (reg_data << MVPP2_TXP_SCHED_DISQ_OFFSET));
+
+ /* Wait for all Tx activity to terminate. */
+ delay = 0;
+ do {
+ if (delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) {
+ netdev_warn(port->dev,
+ "Tx stop timed out, status=0x%08x\n",
+ reg_data);
+ break;
+ }
+ mdelay(1);
+ delay++;
+
+ /* Check port TX Command register that all
+ * Tx queues are stopped
+ */
+ reg_data = mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG);
+ } while (reg_data & MVPP2_TXP_SCHED_ENQ_MASK);
+}
+
+/* Rx descriptors helper methods */
+
+/* Get number of Rx descriptors occupied by received packets */
+static inline int
+mvpp2_rxq_received(struct mvpp2_port *port, int rxq_id)
+{
+ u32 val = mvpp2_read(port->priv, MVPP2_RXQ_STATUS_REG(rxq_id));
+
+ return val & MVPP2_RXQ_OCCUPIED_MASK;
+}
+
+/* Update Rx queue status with the number of occupied and available
+ * Rx descriptor slots.
+ */
+static inline void
+mvpp2_rxq_status_update(struct mvpp2_port *port, int rxq_id,
+ int used_count, int free_count)
+{
+ /* Decrement the number of used descriptors and increment count
+ * increment the number of free descriptors.
+ */
+ u32 val = used_count | (free_count << MVPP2_RXQ_NUM_NEW_OFFSET);
+
+ mvpp2_write(port->priv, MVPP2_RXQ_STATUS_UPDATE_REG(rxq_id), val);
+}
+
+/* Get pointer to next RX descriptor to be processed by SW */
+static inline struct mvpp2_rx_desc *
+mvpp2_rxq_next_desc_get(struct mvpp2_rx_queue *rxq)
+{
+ int rx_desc = rxq->next_desc_to_proc;
+
+ rxq->next_desc_to_proc = MVPP2_QUEUE_NEXT_DESC(rxq, rx_desc);
+ prefetch(rxq->descs + rxq->next_desc_to_proc);
+ return rxq->descs + rx_desc;
+}
+
+/* Set rx queue offset */
+static void mvpp2_rxq_offset_set(struct mvpp2_port *port,
+ int prxq, int offset)
+{
+ u32 val;
+
+ /* Convert offset from bytes to units of 32 bytes */
+ offset = offset >> 5;
+
+ val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq));
+ val &= ~MVPP2_RXQ_PACKET_OFFSET_MASK;
+
+ /* Offset is in */
+ val |= ((offset << MVPP2_RXQ_PACKET_OFFSET_OFFS) &
+ MVPP2_RXQ_PACKET_OFFSET_MASK);
mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val);
}
int desc_num, int cpu,
struct mvpp2 *priv)
{
+ u32 txq_dma;
+
/* Allocate memory for TX descriptors */
aggr_txq->descs = buffer_loc.aggr_tx_descs;
aggr_txq->descs_dma = (dma_addr_t)buffer_loc.aggr_tx_descs;
aggr_txq->next_desc_to_proc = mvpp2_read(priv,
MVPP2_AGGR_TXQ_INDEX_REG(cpu));
- /* Set Tx descriptors queue starting address */
- /* indirect access */
- mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu),
- aggr_txq->descs_dma);
+ /* Set Tx descriptors queue starting address indirect
+ * access
+ */
+ if (priv->hw_version == MVPP21)
+ txq_dma = aggr_txq->descs_dma;
+ else
+ txq_dma = aggr_txq->descs_dma >>
+ MVPP22_AGGR_TXQ_DESC_ADDR_OFFS;
+
+ mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu), txq_dma);
mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu), desc_num);
return 0;
struct mvpp2_rx_queue *rxq)
{
+ u32 rxq_dma;
+
rxq->size = port->rx_ring_size;
/* Allocate memory for RX descriptors */
/* Set Rx descriptors queue starting address - indirect access */
mvpp2_write(port->priv, MVPP2_RXQ_NUM_REG, rxq->id);
- mvpp2_write(port->priv, MVPP2_RXQ_DESC_ADDR_REG, rxq->descs_dma);
+ if (port->priv->hw_version == MVPP21)
+ rxq_dma = rxq->descs_dma;
+ else
+ rxq_dma = rxq->descs_dma >> MVPP22_DESC_ADDR_OFFS;
+ mvpp2_write(port->priv, MVPP2_RXQ_DESC_ADDR_REG, rxq_dma);
mvpp2_write(port->priv, MVPP2_RXQ_DESC_SIZE_REG, rxq->size);
mvpp2_write(port->priv, MVPP2_RXQ_INDEX_REG, 0);
mvpp2_write(port->priv, MVPP2_TXQ_PREF_BUF_REG,
MVPP2_PREF_BUF_PTR(desc) | MVPP2_PREF_BUF_SIZE_16 |
- MVPP2_PREF_BUF_THRESH(desc_per_txq/2));
+ MVPP2_PREF_BUF_THRESH(desc_per_txq / 2));
/* WRR / EJP configuration - indirect access */
tx_port_num = mvpp2_egress_port(port);
/* Set hw internals when starting port */
static void mvpp2_start_dev(struct mvpp2_port *port)
{
- mvpp2_gmac_max_rx_size_set(port);
+ switch (port->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_SGMII:
+ mvpp2_gmac_max_rx_size_set(port);
+ default:
+ break;
+ }
+
mvpp2_txp_max_tx_size_set(port);
- mvpp2_port_enable(port);
+ if (port->priv->hw_version == MVPP21)
+ mvpp2_port_enable(port);
+ else
+ gop_port_enable(port, 1);
}
/* Set hw internals when stopping port */
mvpp2_ingress_disable(port);
mvpp2_egress_disable(port);
- mvpp2_port_disable(port);
+
+ if (port->priv->hw_version == MVPP21)
+ mvpp2_port_disable(port);
+ else
+ gop_port_enable(port, 0);
}
-static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port)
+static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port)
{
struct phy_device *phy_dev;
if (!port->init || port->link == 0) {
- phy_dev = phy_connect(port->priv->bus, port->phyaddr, dev,
+ phy_dev = phy_connect(port->bus, port->phyaddr, dev,
port->phy_interface);
port->phy_dev = phy_dev;
if (!phy_dev) {
netdev_err(port->dev, "cannot connect to phy\n");
- return -ENODEV;
+ return;
}
phy_dev->supported &= PHY_GBIT_FEATURES;
phy_dev->advertising = phy_dev->supported;
phy_config(phy_dev);
phy_startup(phy_dev);
- if (!phy_dev->link) {
+ if (!phy_dev->link)
printf("%s: No link\n", phy_dev->dev->name);
- return -1;
- }
-
- port->init = 1;
+ else
+ port->init = 1;
} else {
mvpp2_egress_enable(port);
mvpp2_ingress_enable(port);
}
-
- return 0;
}
static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port)
return err;
}
- err = mvpp2_phy_connect(dev, port);
- if (err < 0)
- return err;
-
- mvpp2_link_event(port);
+ if (port->phy_node) {
+ mvpp2_phy_connect(dev, port);
+ mvpp2_link_event(port);
+ } else {
+ mvpp2_egress_enable(port);
+ mvpp2_ingress_enable(port);
+ }
mvpp2_start_dev(port);
static void mvpp2_port_power_up(struct mvpp2_port *port)
{
- mvpp2_port_mii_set(port);
+ struct mvpp2 *priv = port->priv;
+
+ /* On PPv2.2 the GoP / interface configuration has already been done */
+ if (priv->hw_version == MVPP21)
+ mvpp2_port_mii_set(port);
mvpp2_port_periodic_xon_disable(port);
- mvpp2_port_fc_adv_enable(port);
+ if (priv->hw_version == MVPP21)
+ mvpp2_port_fc_adv_enable(port);
mvpp2_port_reset(port);
}
struct mvpp2_txq_pcpu *txq_pcpu;
int queue, cpu, err;
- if (port->first_rxq + rxq_number > MVPP2_RXQ_TOTAL_NUM)
+ if (port->first_rxq + rxq_number >
+ MVPP2_MAX_PORTS * priv->max_port_rxqs)
return -EINVAL;
/* Disable port */
mvpp2_egress_disable(port);
- mvpp2_port_disable(port);
+ if (priv->hw_version == MVPP21)
+ mvpp2_port_disable(port);
+ else
+ gop_port_enable(port, 0);
port->txqs = devm_kcalloc(dev, txq_number, sizeof(*port->txqs),
GFP_KERNEL);
port->rxqs[queue] = rxq;
}
- /* Configure Rx queue group interrupt for this port */
- mvpp2_write(priv, MVPP2_ISR_RXQ_GROUP_REG(port->id), CONFIG_MV_ETH_RXQ);
/* Create Rx descriptor rings */
for (queue = 0; queue < rxq_number; queue++) {
return 0;
}
-/* Ports initialization */
-static int mvpp2_port_probe(struct udevice *dev,
- struct mvpp2_port *port,
- int port_node,
- struct mvpp2 *priv,
- int *next_first_rxq)
+static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port)
{
+ int port_node = dev_of_offset(dev);
+ const char *phy_mode_str;
int phy_node;
u32 id;
- u32 phyaddr;
- const char *phy_mode_str;
+ u32 phyaddr = 0;
int phy_mode = -1;
- int priv_common_regs_num = 2;
- int err;
+
+ /* Default mdio_base from the same eth base */
+ if (port->priv->hw_version == MVPP21)
+ port->mdio_base = port->priv->lms_base + MVPP21_SMI;
+ else
+ port->mdio_base = port->priv->iface_base + MVPP22_SMI;
phy_node = fdtdec_lookup_phandle(gd->fdt_blob, port_node, "phy");
- if (phy_node < 0) {
- dev_err(&pdev->dev, "missing phy\n");
- return -ENODEV;
+
+ if (phy_node > 0) {
+ ofnode phy_ofnode;
+ fdt_addr_t phy_base;
+
+ phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0);
+ if (phyaddr < 0) {
+ dev_err(&pdev->dev, "could not find phy address\n");
+ return -1;
+ }
+
+ phy_ofnode = ofnode_get_parent(offset_to_ofnode(phy_node));
+ phy_base = ofnode_get_addr(phy_ofnode);
+ port->mdio_base = (void *)phy_base;
+
+ if (port->mdio_base < 0) {
+ dev_err(&pdev->dev, "could not find mdio base address\n");
+ return -1;
+ }
+ } else {
+ phy_node = 0;
}
phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, "phy-mode", NULL);
return -EINVAL;
}
- phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0);
+#ifdef CONFIG_DM_GPIO
+ gpio_request_by_name(dev, "phy-reset-gpios", 0,
+ &port->phy_reset_gpio, GPIOD_IS_OUT);
+ gpio_request_by_name(dev, "marvell,sfp-tx-disable-gpio", 0,
+ &port->phy_tx_disable_gpio, GPIOD_IS_OUT);
+#endif
+
+ /*
+ * ToDo:
+ * Not sure if this DT property "phy-speed" will get accepted, so
+ * this might change later
+ */
+ /* Get phy-speed for SGMII 2.5Gbps vs 1Gbps setup */
+ port->phy_speed = fdtdec_get_int(gd->fdt_blob, port_node,
+ "phy-speed", 1000);
- port->priv = priv;
port->id = id;
- port->first_rxq = *next_first_rxq;
+ if (port->priv->hw_version == MVPP21)
+ port->first_rxq = port->id * rxq_number;
+ else
+ port->first_rxq = port->id * port->priv->max_port_rxqs;
port->phy_node = phy_node;
port->phy_interface = phy_mode;
port->phyaddr = phyaddr;
- port->base = (void __iomem *)dev_get_addr_index(dev->parent,
- priv_common_regs_num
- + id);
- if (IS_ERR(port->base))
- return PTR_ERR(port->base);
+ return 0;
+}
+
+#ifdef CONFIG_DM_GPIO
+/* Port GPIO initialization */
+static void mvpp2_gpio_init(struct mvpp2_port *port)
+{
+ if (dm_gpio_is_valid(&port->phy_reset_gpio)) {
+ dm_gpio_set_value(&port->phy_reset_gpio, 1);
+ mdelay(10);
+ dm_gpio_set_value(&port->phy_reset_gpio, 0);
+ }
+
+ if (dm_gpio_is_valid(&port->phy_tx_disable_gpio))
+ dm_gpio_set_value(&port->phy_tx_disable_gpio, 0);
+}
+#endif
+
+/* Ports initialization */
+static int mvpp2_port_probe(struct udevice *dev,
+ struct mvpp2_port *port,
+ int port_node,
+ struct mvpp2 *priv)
+{
+ int err;
port->tx_ring_size = MVPP2_MAX_TXD;
port->rx_ring_size = MVPP2_MAX_RXD;
err = mvpp2_port_init(dev, port);
if (err < 0) {
- dev_err(&pdev->dev, "failed to init port %d\n", id);
+ dev_err(&pdev->dev, "failed to init port %d\n", port->id);
return err;
}
mvpp2_port_power_up(port);
- /* Increment the first Rx queue number to be used by the next port */
- *next_first_rxq += CONFIG_MV_ETH_RXQ;
- priv->port_list[id] = port;
+#ifdef CONFIG_DM_GPIO
+ mvpp2_gpio_init(port);
+#endif
+
+ priv->port_list[port->id] = port;
+ priv->num_ports++;
return 0;
}
int port;
for (port = 0; port < MVPP2_MAX_PORTS; port++) {
- mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port),
- MVPP2_RX_FIFO_PORT_DATA_SIZE);
- mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
- MVPP2_RX_FIFO_PORT_ATTR_SIZE);
+ if (priv->hw_version == MVPP22) {
+ if (port == 0) {
+ mvpp2_write(priv,
+ MVPP2_RX_DATA_FIFO_SIZE_REG(port),
+ MVPP22_RX_FIFO_10GB_PORT_DATA_SIZE);
+ mvpp2_write(priv,
+ MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
+ MVPP22_RX_FIFO_10GB_PORT_ATTR_SIZE);
+ } else if (port == 1) {
+ mvpp2_write(priv,
+ MVPP2_RX_DATA_FIFO_SIZE_REG(port),
+ MVPP22_RX_FIFO_2_5GB_PORT_DATA_SIZE);
+ mvpp2_write(priv,
+ MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
+ MVPP22_RX_FIFO_2_5GB_PORT_ATTR_SIZE);
+ } else {
+ mvpp2_write(priv,
+ MVPP2_RX_DATA_FIFO_SIZE_REG(port),
+ MVPP22_RX_FIFO_1GB_PORT_DATA_SIZE);
+ mvpp2_write(priv,
+ MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
+ MVPP22_RX_FIFO_1GB_PORT_ATTR_SIZE);
+ }
+ } else {
+ mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port),
+ MVPP21_RX_FIFO_PORT_DATA_SIZE);
+ mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port),
+ MVPP21_RX_FIFO_PORT_ATTR_SIZE);
+ }
}
mvpp2_write(priv, MVPP2_RX_MIN_PKT_SIZE_REG,
mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
}
+/* Initialize Tx FIFO's */
+static void mvpp2_tx_fifo_init(struct mvpp2 *priv)
+{
+ int port, val;
+
+ for (port = 0; port < MVPP2_MAX_PORTS; port++) {
+ /* Port 0 supports 10KB TX FIFO */
+ if (port == 0) {
+ val = MVPP2_TX_FIFO_DATA_SIZE_10KB &
+ MVPP22_TX_FIFO_SIZE_MASK;
+ } else {
+ val = MVPP2_TX_FIFO_DATA_SIZE_3KB &
+ MVPP22_TX_FIFO_SIZE_MASK;
+ }
+ mvpp2_write(priv, MVPP22_TX_FIFO_SIZE_REG(port), val);
+ }
+}
+
+static void mvpp2_axi_init(struct mvpp2 *priv)
+{
+ u32 val, rdval, wrval;
+
+ mvpp2_write(priv, MVPP22_BM_ADDR_HIGH_RLS_REG, 0x0);
+
+ /* AXI Bridge Configuration */
+
+ rdval = MVPP22_AXI_CODE_CACHE_RD_CACHE
+ << MVPP22_AXI_ATTR_CACHE_OFFS;
+ rdval |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
+ << MVPP22_AXI_ATTR_DOMAIN_OFFS;
+
+ wrval = MVPP22_AXI_CODE_CACHE_WR_CACHE
+ << MVPP22_AXI_ATTR_CACHE_OFFS;
+ wrval |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
+ << MVPP22_AXI_ATTR_DOMAIN_OFFS;
+
+ /* BM */
+ mvpp2_write(priv, MVPP22_AXI_BM_WR_ATTR_REG, wrval);
+ mvpp2_write(priv, MVPP22_AXI_BM_RD_ATTR_REG, rdval);
+
+ /* Descriptors */
+ mvpp2_write(priv, MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG, rdval);
+ mvpp2_write(priv, MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG, wrval);
+ mvpp2_write(priv, MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG, rdval);
+ mvpp2_write(priv, MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG, wrval);
+
+ /* Buffer Data */
+ mvpp2_write(priv, MVPP22_AXI_TX_DATA_RD_ATTR_REG, rdval);
+ mvpp2_write(priv, MVPP22_AXI_RX_DATA_WR_ATTR_REG, wrval);
+
+ val = MVPP22_AXI_CODE_CACHE_NON_CACHE
+ << MVPP22_AXI_CODE_CACHE_OFFS;
+ val |= MVPP22_AXI_CODE_DOMAIN_SYSTEM
+ << MVPP22_AXI_CODE_DOMAIN_OFFS;
+ mvpp2_write(priv, MVPP22_AXI_RD_NORMAL_CODE_REG, val);
+ mvpp2_write(priv, MVPP22_AXI_WR_NORMAL_CODE_REG, val);
+
+ val = MVPP22_AXI_CODE_CACHE_RD_CACHE
+ << MVPP22_AXI_CODE_CACHE_OFFS;
+ val |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
+ << MVPP22_AXI_CODE_DOMAIN_OFFS;
+
+ mvpp2_write(priv, MVPP22_AXI_RD_SNOOP_CODE_REG, val);
+
+ val = MVPP22_AXI_CODE_CACHE_WR_CACHE
+ << MVPP22_AXI_CODE_CACHE_OFFS;
+ val |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM
+ << MVPP22_AXI_CODE_DOMAIN_OFFS;
+
+ mvpp2_write(priv, MVPP22_AXI_WR_SNOOP_CODE_REG, val);
+}
+
/* Initialize network controller common part HW */
static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv)
{
u32 val;
/* Checks for hardware constraints (U-Boot uses only one rxq) */
- if ((rxq_number > MVPP2_MAX_RXQ) || (txq_number > MVPP2_MAX_TXQ)) {
+ if ((rxq_number > priv->max_port_rxqs) ||
+ (txq_number > MVPP2_MAX_TXQ)) {
dev_err(&pdev->dev, "invalid queue size parameter\n");
return -EINVAL;
}
- /* MBUS windows configuration */
- dram_target_info = mvebu_mbus_dram_info();
- if (dram_target_info)
- mvpp2_conf_mbus_windows(dram_target_info, priv);
+ if (priv->hw_version == MVPP22)
+ mvpp2_axi_init(priv);
+ else {
+ /* MBUS windows configuration */
+ dram_target_info = mvebu_mbus_dram_info();
+ if (dram_target_info)
+ mvpp2_conf_mbus_windows(dram_target_info, priv);
+ }
- /* Disable HW PHY polling */
- val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
- val |= MVPP2_PHY_AN_STOP_SMI0_MASK;
- writel(val, priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
+ if (priv->hw_version == MVPP21) {
+ /* Disable HW PHY polling */
+ val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
+ val |= MVPP2_PHY_AN_STOP_SMI0_MASK;
+ writel(val, priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
+ } else {
+ /* Enable HW PHY polling */
+ val = readl(priv->iface_base + MVPP22_SMI_MISC_CFG_REG);
+ val |= MVPP22_SMI_POLLING_EN;
+ writel(val, priv->iface_base + MVPP22_SMI_MISC_CFG_REG);
+ }
/* Allocate and initialize aggregated TXQs */
priv->aggr_txqs = devm_kcalloc(dev, num_present_cpus(),
/* Rx Fifo Init */
mvpp2_rx_fifo_init(priv);
- /* Reset Rx queue group interrupt configuration */
- for (i = 0; i < MVPP2_MAX_PORTS; i++)
- mvpp2_write(priv, MVPP2_ISR_RXQ_GROUP_REG(i),
- CONFIG_MV_ETH_RXQ);
+ /* Tx Fifo Init */
+ if (priv->hw_version == MVPP22)
+ mvpp2_tx_fifo_init(priv);
- writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
- priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG);
+ if (priv->hw_version == MVPP21)
+ writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
+ priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG);
/* Allow cache snoop when transmiting packets */
mvpp2_write(priv, MVPP2_TX_SNOOP_REG, 0x1);
/* SMI / MDIO functions */
-static int smi_wait_ready(struct mvpp2 *priv)
+static int smi_wait_ready(struct mvpp2_port *priv)
{
u32 timeout = MVPP2_SMI_TIMEOUT;
u32 smi_reg;
/* wait till the SMI is not busy */
do {
/* read smi register */
- smi_reg = readl(priv->lms_base + MVPP2_SMI);
+ smi_reg = readl(priv->mdio_base);
if (timeout-- == 0) {
printf("Error: SMI busy timeout\n");
return -EFAULT;
*/
static int mpp2_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
{
- struct mvpp2 *priv = bus->priv;
+ struct mvpp2_port *priv = bus->priv;
u32 smi_reg;
u32 timeout;
| MVPP2_SMI_OPCODE_READ;
/* write the smi register */
- writel(smi_reg, priv->lms_base + MVPP2_SMI);
+ writel(smi_reg, priv->mdio_base);
/* wait till read value is ready */
timeout = MVPP2_SMI_TIMEOUT;
do {
/* read smi register */
- smi_reg = readl(priv->lms_base + MVPP2_SMI);
+ smi_reg = readl(priv->mdio_base);
if (timeout-- == 0) {
printf("Err: SMI read ready timeout\n");
return -EFAULT;
for (timeout = 0; timeout < MVPP2_SMI_TIMEOUT; timeout++)
;
- return readl(priv->lms_base + MVPP2_SMI) & MVPP2_SMI_DATA_MASK;
+ return readl(priv->mdio_base) & MVPP2_SMI_DATA_MASK;
}
/*
static int mpp2_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
u16 value)
{
- struct mvpp2 *priv = bus->priv;
+ struct mvpp2_port *priv = bus->priv;
u32 smi_reg;
/* check parameters */
smi_reg &= ~MVPP2_SMI_OPCODE_READ;
/* write the smi register */
- writel(smi_reg, priv->lms_base + MVPP2_SMI);
+ writel(smi_reg, priv->mdio_base);
return 0;
}
int pool, rx_bytes, err;
int rx_received;
struct mvpp2_rx_queue *rxq;
- u32 cause_rx_tx, cause_rx, cause_misc;
u8 *data;
- cause_rx_tx = mvpp2_read(port->priv,
- MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
- cause_rx_tx &= ~MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
- cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
- if (!cause_rx_tx && !cause_misc)
- return 0;
-
- cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
+ if (port->phy_node)
+ if (!port->phy_dev->link)
+ return 0;
/* Process RX packets */
- cause_rx |= port->pending_cause_rx;
- rxq = mvpp2_get_rx_queue(port, cause_rx);
+ rxq = port->rxqs[0];
/* Get number of received packets and clamp the to-do */
rx_received = mvpp2_rxq_received(port, rxq->id);
return rx_bytes;
}
-/* Drain Txq */
-static void mvpp2_txq_drain(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
- int enable)
-{
- u32 val;
-
- mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id);
- val = mvpp2_read(port->priv, MVPP2_TXQ_PREF_BUF_REG);
- if (enable)
- val |= MVPP2_TXQ_DRAIN_EN_MASK;
- else
- val &= ~MVPP2_TXQ_DRAIN_EN_MASK;
- mvpp2_write(port->priv, MVPP2_TXQ_PREF_BUF_REG, val);
-}
-
static int mvpp2_send(struct udevice *dev, void *packet, int length)
{
struct mvpp2_port *port = dev_get_priv(dev);
int tx_done;
int timeout;
+ if (port->phy_node)
+ if (!port->phy_dev->link)
+ return 0;
+
txq = port->txqs[0];
aggr_txq = &port->priv->aggr_txqs[smp_processor_id()];
tx_done = mvpp2_txq_pend_desc_num_get(port, txq);
} while (tx_done);
- /* Enable TXQ drain */
- mvpp2_txq_drain(port, txq, 1);
-
timeout = 0;
do {
if (timeout++ > 10000) {
tx_done = mvpp2_txq_sent_desc_proc(port, txq);
} while (!tx_done);
- /* Disable TXQ drain */
- mvpp2_txq_drain(port, txq, 0);
-
return 0;
}
/* Reconfigure parser accept the original MAC address */
mvpp2_prs_update_mac_da(port, port->dev_addr);
- mvpp2_port_power_up(port);
+ switch (port->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_SGMII:
+ mvpp2_port_power_up(port);
+ default:
+ break;
+ }
mvpp2_open(dev, port);
mvpp2_cleanup_txqs(port);
}
-static int mvpp2_probe(struct udevice *dev)
+static int mvpp2_write_hwaddr(struct udevice *dev)
{
struct mvpp2_port *port = dev_get_priv(dev);
- struct mvpp2 *priv = dev_get_priv(dev->parent);
- int err;
- /* Initialize network controller */
- err = mvpp2_init(dev, priv);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to initialize controller\n");
- return err;
- }
-
- return mvpp2_port_probe(dev, port, dev_of_offset(dev), priv,
- &buffer_loc.first_rxq);
+ return mvpp2_prs_update_mac_da(port, port->dev_addr);
}
-static const struct eth_ops mvpp2_ops = {
- .start = mvpp2_start,
- .send = mvpp2_send,
- .recv = mvpp2_recv,
- .stop = mvpp2_stop,
-};
+static int mvpp22_smi_phy_addr_cfg(struct mvpp2_port *port)
+{
+ writel(port->phyaddr, port->priv->iface_base +
+ MVPP22_SMI_PHY_ADDR_REG(port->gop_id));
-static struct driver mvpp2_driver = {
- .name = "mvpp2",
- .id = UCLASS_ETH,
- .probe = mvpp2_probe,
- .ops = &mvpp2_ops,
- .priv_auto_alloc_size = sizeof(struct mvpp2_port),
- .platdata_auto_alloc_size = sizeof(struct eth_pdata),
-};
+ return 0;
+}
-/*
- * Use a MISC device to bind the n instances (child nodes) of the
- * network base controller in UCLASS_ETH.
- */
static int mvpp2_base_probe(struct udevice *dev)
{
struct mvpp2 *priv = dev_get_priv(dev);
- struct mii_dev *bus;
void *bd_space;
u32 size = 0;
int i;
for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) {
buffer_loc.bm_pool[i] =
(unsigned long *)((unsigned long)bd_space + size);
- size += MVPP2_BM_POOL_SIZE_MAX * sizeof(u32);
+ if (priv->hw_version == MVPP21)
+ size += MVPP2_BM_POOL_SIZE_MAX * 2 * sizeof(u32);
+ else
+ size += MVPP2_BM_POOL_SIZE_MAX * 2 * sizeof(u64);
}
for (i = 0; i < MVPP2_BM_LONG_BUF_NUM; i++) {
size += RX_BUFFER_SIZE;
}
+ /* Clear the complete area so that all descriptors are cleared */
+ memset(bd_space, 0, size);
+
/* Save base addresses for later use */
- priv->base = (void *)dev_get_addr_index(dev, 0);
+ priv->base = (void *)devfdt_get_addr_index(dev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
- priv->lms_base = (void *)dev_get_addr_index(dev, 1);
- if (IS_ERR(priv->lms_base))
- return PTR_ERR(priv->lms_base);
+ if (priv->hw_version == MVPP21) {
+ priv->lms_base = (void *)devfdt_get_addr_index(dev, 1);
+ if (IS_ERR(priv->lms_base))
+ return PTR_ERR(priv->lms_base);
+ } else {
+ priv->iface_base = (void *)devfdt_get_addr_index(dev, 1);
+ if (IS_ERR(priv->iface_base))
+ return PTR_ERR(priv->iface_base);
+
+ /* Store common base addresses for all ports */
+ priv->mpcs_base = priv->iface_base + MVPP22_MPCS;
+ priv->xpcs_base = priv->iface_base + MVPP22_XPCS;
+ priv->rfu1_base = priv->iface_base + MVPP22_RFU1;
+ }
+
+ if (priv->hw_version == MVPP21)
+ priv->max_port_rxqs = 8;
+ else
+ priv->max_port_rxqs = 32;
+
+ return 0;
+}
+
+static int mvpp2_probe(struct udevice *dev)
+{
+ struct mvpp2_port *port = dev_get_priv(dev);
+ struct mvpp2 *priv = dev_get_priv(dev->parent);
+ struct mii_dev *bus;
+ int err;
+
+ /* Only call the probe function for the parent once */
+ if (!priv->probe_done)
+ err = mvpp2_base_probe(dev->parent);
+
+ port->priv = dev_get_priv(dev->parent);
- /* Finally create and register the MDIO bus driver */
+ /* Create and register the MDIO bus driver */
bus = mdio_alloc();
if (!bus) {
printf("Failed to allocate MDIO bus\n");
bus->read = mpp2_mdio_read;
bus->write = mpp2_mdio_write;
snprintf(bus->name, sizeof(bus->name), dev->name);
- bus->priv = (void *)priv;
- priv->bus = bus;
+ bus->priv = (void *)port;
+ port->bus = bus;
+
+ err = mdio_register(bus);
+ if (err)
+ return err;
+
+ err = phy_info_parse(dev, port);
+ if (err)
+ return err;
+
+ /*
+ * We need the port specific io base addresses at this stage, since
+ * gop_port_init() accesses these registers
+ */
+ if (priv->hw_version == MVPP21) {
+ int priv_common_regs_num = 2;
+
+ port->base = (void __iomem *)devfdt_get_addr_index(
+ dev->parent, priv_common_regs_num + port->id);
+ if (IS_ERR(port->base))
+ return PTR_ERR(port->base);
+ } else {
+ port->gop_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
+ "gop-port-id", -1);
+ if (port->id == -1) {
+ dev_err(&pdev->dev, "missing gop-port-id value\n");
+ return -EINVAL;
+ }
+
+ port->base = priv->iface_base + MVPP22_PORT_BASE +
+ port->gop_id * MVPP22_PORT_OFFSET;
+
+ /* Set phy address of the port */
+ if(port->phy_node)
+ mvpp22_smi_phy_addr_cfg(port);
+
+ /* GoP Init */
+ gop_port_init(port);
+ }
+
+ if (!priv->probe_done) {
+ /* Initialize network controller */
+ err = mvpp2_init(dev, priv);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to initialize controller\n");
+ return err;
+ }
+ priv->num_ports = 0;
+ priv->probe_done = 1;
+ }
+
+ err = mvpp2_port_probe(dev, port, dev_of_offset(dev), priv);
+ if (err)
+ return err;
+
+ if (priv->hw_version == MVPP22) {
+ priv->netc_config |= mvpp2_netc_cfg_create(port->gop_id,
+ port->phy_interface);
+
+ /* Netcomplex configurations for all ports */
+ gop_netc_init(priv, MV_NETC_FIRST_PHASE);
+ gop_netc_init(priv, MV_NETC_SECOND_PHASE);
+ }
+
+ return 0;
+}
+
+/*
+ * Empty BM pool and stop its activity before the OS is started
+ */
+static int mvpp2_remove(struct udevice *dev)
+{
+ struct mvpp2_port *port = dev_get_priv(dev);
+ struct mvpp2 *priv = port->priv;
+ int i;
- return mdio_register(bus);
+ priv->num_ports--;
+
+ if (priv->num_ports)
+ return 0;
+
+ for (i = 0; i < MVPP2_BM_POOLS_NUM; i++)
+ mvpp2_bm_pool_destroy(dev, priv, &priv->bm_pools[i]);
+
+ return 0;
}
+static const struct eth_ops mvpp2_ops = {
+ .start = mvpp2_start,
+ .send = mvpp2_send,
+ .recv = mvpp2_recv,
+ .stop = mvpp2_stop,
+ .write_hwaddr = mvpp2_write_hwaddr
+};
+
+static struct driver mvpp2_driver = {
+ .name = "mvpp2",
+ .id = UCLASS_ETH,
+ .probe = mvpp2_probe,
+ .remove = mvpp2_remove,
+ .ops = &mvpp2_ops,
+ .priv_auto_alloc_size = sizeof(struct mvpp2_port),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ACTIVE_DMA,
+};
+
+/*
+ * Use a MISC device to bind the n instances (child nodes) of the
+ * network base controller in UCLASS_ETH.
+ */
static int mvpp2_base_bind(struct udevice *parent)
{
const void *blob = gd->fdt_blob;
char *name;
int subnode;
u32 id;
+ int base_id_add;
/* Lookup eth driver */
drv = lists_uclass_lookup(UCLASS_ETH);
return -ENOENT;
}
+ base_id_add = base_id;
+
fdt_for_each_subnode(subnode, blob, node) {
+ /* Increment base_id for all subnodes, also the disabled ones */
+ base_id++;
+
/* Skip disabled ports */
if (!fdtdec_get_is_enabled(blob, subnode))
continue;
return -ENOMEM;
id = fdtdec_get_int(blob, subnode, "port-id", -1);
+ id += base_id_add;
name = calloc(1, 16);
+ if (!name) {
+ free(plat);
+ return -ENOMEM;
+ }
sprintf(name, "mvpp2-%d", id);
/* Create child device UCLASS_ETH and bind it */
.compatible = "marvell,armada-375-pp2",
.data = MVPP21,
},
+ {
+ .compatible = "marvell,armada-7k-pp22",
+ .data = MVPP22,
+ },
{ }
};
.id = UCLASS_MISC,
.of_match = mvpp2_ids,
.bind = mvpp2_base_bind,
- .probe = mvpp2_base_probe,
.priv_auto_alloc_size = sizeof(struct mvpp2),
};