diff --git a/arch/arm/dts/ipq5018-emulation.dts b/arch/arm/dts/ipq5018-emulation.dts index f5c41ac8be..927aa4232d 100644 --- a/arch/arm/dts/ipq5018-emulation.dts +++ b/arch/arm/dts/ipq5018-emulation.dts @@ -23,6 +23,7 @@ console = "/serial@78AF000"; mmc = "/sdhci@7804000"; i2c0 = "/i2c@78b6000"; + gmac_gpio = "/gmac_gpio"; }; mmc: sdhci@7804000 { @@ -38,4 +39,23 @@ gpt_freq_hz = <240000>; }; + gmac_cfg { + gmac_count = <2>; + + gmac1_cfg { + unit = <0>; + base = <0x39C00000>; + phy_address = <7>; + phy_name = "IPQ MDIO0"; + }; + + gmac2_cfg { + unit = <1>; + base = <0x39D00000>; + phy_address = <1>; + phy_name = "IPQ MDIO1"; + }; + }; + + gmac_gpio{}; }; diff --git a/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h b/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h new file mode 100644 index 0000000000..e1643c5686 --- /dev/null +++ b/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _IPQ5018_GMAC_H +#define _IPQ5018_GMAC_H +#include +#include +#include + +#define CONFIG_MACRESET_TIMEOUT (3 * CONFIG_SYS_HZ) +#define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ) +#define CONFIG_PHYRESET_TIMEOUT (3 * CONFIG_SYS_HZ) +#define CONFIG_AUTONEG_TIMEOUT (5 * CONFIG_SYS_HZ) +/* MAC configuration register definitions */ +#define FRAMEBURSTENABLE (1 << 21) +#define MII_PORTSELECT (1 << 15) +#define FES_100 (1 << 14) +#define DISABLERXOWN (1 << 13) +#define FULLDPLXMODE (1 << 11) +#define RXENABLE (1 << 2) +#define TXENABLE (1 << 3) +#define DW_DMA_BASE_OFFSET (0x1000) + +/* Poll demand definitions */ +#define POLL_DATA (0x0) + + +/* Descriptior related definitions */ +#define MAC_MAX_FRAME_SZ (1600) + +/* + * txrx_status definitions + */ + +/* tx status bits definitions */ +#define DESC_TXSTS_OWNBYDMA (1 << 31) +#define DESC_TXSTS_TXINT (1 << 30) +#define DESC_TXSTS_TXLAST (1 << 29) +#define DESC_TXSTS_TXFIRST (1 << 28) +#define DESC_TXSTS_TXCRCDIS (1 << 27) + +#define DESC_TXSTS_TXPADDIS (1 << 26) +#define DESC_TXSTS_TXCHECKINSCTRL (3 << 22) +#define DESC_TXSTS_TXRINGEND (1 << 21) +#define DESC_TXSTS_TXCHAIN (1 << 20) +#define DESC_TXSTS_MSK (0x1FFFF << 0) + +/* rx status bits definitions */ +#define DESC_RXSTS_OWNBYDMA (1 << 31) +#define DESC_RXSTS_DAFILTERFAIL (1 << 30) +#define DESC_RXSTS_FRMLENMSK (0x3FFF << 16) +#define DESC_RXSTS_FRMLENSHFT (16) + +#define DESC_RXSTS_ERROR (1 << 15) +#define DESC_RXSTS_RXTRUNCATED (1 << 14) +#define DESC_RXSTS_SAFILTERFAIL (1 << 13) +#define DESC_RXSTS_RXIPC_GIANTFRAME (1 << 12) +#define DESC_RXSTS_RXDAMAGED (1 << 11) +#define DESC_RXSTS_RXVLANTAG (1 << 10) +#define DESC_RXSTS_RXFIRST (1 << 9) +#define DESC_RXSTS_RXLAST (1 << 8) +#define DESC_RXSTS_RXIPC_GIANT (1 << 7) +#define DESC_RXSTS_RXCOLLISION (1 << 6) +#define DESC_RXSTS_RXFRAMEETHER (1 << 5) +#define DESC_RXSTS_RXWATCHDOG (1 << 4) +#define DESC_RXSTS_RXMIIERROR (1 << 3) +#define DESC_RXSTS_RXDRIBBLING (1 << 2) +#define DESC_RXSTS_RXCRC (1 << 1) + +/* + * dmamac_cntl definitions + */ + +/* tx control bits definitions */ +#if defined(CONFIG_DW_ALTDESCRIPTOR) + +#define DESC_TXCTRL_SIZE1MASK (0x1FFF << 0) +#define DESC_TXCTRL_SIZE1SHFT (0) +#define DESC_TXCTRL_SIZE2MASK (0x1FFF << 16) +#define DESC_TXCTRL_SIZE2SHFT (16) + +#else + +#define DESC_TXCTRL_TXINT (1 << 31) +#define DESC_TXCTRL_TXLAST (1 << 30) +#define DESC_TXCTRL_TXFIRST (1 << 29) +#define DESC_TXCTRL_TXCHECKINSCTRL (3 << 27) +#define DESC_TXCTRL_TXCRCDIS (1 << 26) +#define DESC_TXCTRL_TXRINGEND (1 << 25) +#define DESC_TXCTRL_TXCHAIN (1 << 24) + +#define DESC_TXCTRL_SIZE1MASK (0x7FF << 0) +#define DESC_TXCTRL_SIZE1SHFT (0) +#define DESC_TXCTRL_SIZE2MASK (0x7FF << 11) +#define DESC_TXCTRL_SIZE2SHFT (11) + +#endif + +/* rx control bits definitions */ +#if defined(CONFIG_DW_ALTDESCRIPTOR) + +#define DESC_RXCTRL_RXINTDIS (1 << 31) +#define DESC_RXCTRL_RXRINGEND (1 << 15) +#define DESC_RXCTRL_RXCHAIN (1 << 14) + +#define DESC_RXCTRL_SIZE1MASK (0x1FFF << 0) +#define DESC_RXCTRL_SIZE1SHFT (0) +#define DESC_RXCTRL_SIZE2MASK (0x1FFF << 16) +#define DESC_RXCTRL_SIZE2SHFT (16) + +#else + +#define DESC_RXCTRL_RXINTDIS (1 << 31) +#define DESC_RXCTRL_RXRINGEND (1 << 25) +#define DESC_RXCTRL_RXCHAIN (1 << 24) + +#define DESC_RXCTRL_SIZE1MASK (0x7FF << 0) +#define DESC_RXCTRL_SIZE1SHFT (0) +#define DESC_RXCTRL_SIZE2MASK (0x7FF << 11) +#define DESC_RXCTRL_SIZE2SHFT (11) + +#endif + +/* Speed specific definitions */ +#define NETDEV_TX_BUSY (1) + +/* Duplex mode specific definitions */ +#define HALF_DUPLEX (1) +#define FULL_DUPLEX (2) + +/* Bus mode register definitions */ +#define FIXEDBURST (1 << 16) +#define PRIORXTX_41 (3 << 14) +#define PRIORXTX_31 (2 << 14) +#define PRIORXTX_21 (1 << 14) +#define PRIORXTX_11 (0 << 14) +#define BURST_1 (1 << 8) +#define BURST_2 (2 << 8) +#define BURST_4 (4 << 8) +#define BURST_8 (8 << 8) +#define BURST_16 (16 << 8) +#define BURST_32 (32 << 8) +#define RXHIGHPRIO (1 << 1) +#define DMAMAC_SRST (1 << 0) +#define DMA_ARB (1 << 1) +#define DESC_SKIP_LEN_0 (0 << 2) +#define DMA_INT_DISABLE (0 << 0) +/* Operation mode definitions */ +#define STOREFORWARD (1 << 21) +#define FLUSHTXFIFO (1 << 20) +#define TXSTART (1 << 13) +#define TXSECONDFRAME (1 << 2) +#define RXSTART (1 << 1) +#define RX_THRESHOLD_128 (3 << 3) +#define OP_SECOND_FRAME (1 << 2) + +/* GMAC config definitions */ +#define MII_PORT_SELECT (1 << 15) +#define GMII_PORT_SELECT (0 << 15) +#define FRAME_BURST_ENABLE (1 << 21) +#define JUMBO_FRAME_ENABLE (1 << 20) +#define HALF_DUPLEX_ENABLE (0 << 11) +#define FULL_DUPLEX_ENABLE (1 << 11) +#define TX_ENABLE (1 << 3) +#define RX_ENABLE (1 << 2) +#define RX_IPC_OFFLOAD (1 << 10) + +/* GMAC Fram filter definitions */ +#define GMAC_FRAME_RX_ALL (1 << 31) +#define PROMISCUOUS_MODE_ON (1 << 0) +#define DISABLE_BCAST_FRAMES (1 << 5) + +/* DMA Flow control definitions */ +#define FULL_3KB (1 << 10) +#define HW_FLW_CNTL_ENABLE (1 << 8) + +/* GMAC Flow control definitions */ +#define RX_FLW_CNTL_ENABLE (1 << 2) +#define TX_FLW_CNTL_ENABLE (1 << 1) + + +/* Descriptor definitions */ +#define TX_END_OF_RING (1 << 21) +#define RX_END_OF_RING (1 << 15) + +#define NO_OF_TX_DESC 8 +#define NO_OF_RX_DESC PKTBUFSRX +#define MAX_WAIT 1000 + +#define CACHE_LINE_SIZE (CONFIG_SYS_CACHELINE_SIZE) + +#define VLAN_ETH_FRAME_LEN 1518 +#define ETH_ZLEN 60 +#define ETH_HLEN 12 +#define ETH_FCS_LEN 4 +#define VLAN_HLEN 4 +#define NET_IP_ALIGN 2 + +#define ETHERNET_EXTRA (NET_IP_ALIGN + 2 * CACHE_LINE_SIZE) +#define ETH_MAX_FRAME_LEN (VLAN_ETH_FRAME_LEN + \ + ETH_FCS_LEN + \ + ((4 - NET_IP_ALIGN) & 0x3)) +typedef struct +{ + volatile u32 status; /* Status */ + volatile u32 length; /* Buffer 1 and Buffer 2 length */ + volatile u32 buffer1; /* Network Buffer 1 pointer (Dma-able) */ + volatile u32 data1; /* This holds virtual address of buffer1, not used by DMA */ + /* Following is used only by driver */ + volatile u32 extstatus; /* Extended status of a Rx Descriptor */ + volatile u32 reserved1; /* Reserved word */ + volatile u32 timestamplow; /* Lower 32 bits of the 64 bit timestamp value */ + volatile u32 timestamphigh; /* Higher 32 bits of the 64 bit timestamp value */ +} ipq_gmac_desc_t ; + +#define IPQ5018_GMAC_PORT 2 +#define IPQ5018_PHY_MAX 2 + +struct ipq_eth_dev { + uint phy_address; + uint no_of_phys; + uint interface; + uint sw_configured; + uint speed; + uint duplex; + uint phy_configured; + uint mac_unit; + uint mac_ps; + int link_printed; + u32 padding; + ipq_gmac_desc_t *desc_tx[NO_OF_TX_DESC]; + ipq_gmac_desc_t *desc_rx[NO_OF_RX_DESC]; + uint next_tx; + uint next_rx; + int txdesc_count; + int rxdesc_count; + struct eth_mac_regs *mac_regs_p; + struct eth_dma_regs *dma_regs_p; + struct eth_device *dev; + struct phy_ops *ops[IPQ5018_PHY_MAX]; + const char phy_name[MDIO_NAME_LEN]; + struct ipq_forced_mode *forced_params; + ipq_gmac_board_cfg_t *gmac_board_cfg; +} __attribute__ ((aligned(8))); + +struct eth_mac_regs { + u32 conf; /* 0x00 */ + u32 framefilt; /* 0x04 */ + u32 hashtablehigh; /* 0x08 */ + u32 hashtablelow; /* 0x0c */ + u32 miiaddr; /* 0x10 */ + u32 miidata; /* 0x14 */ + u32 flowcontrol; /* 0x18 */ + u32 vlantag; /* 0x1c */ + u32 version; /* 0x20 */ + u8 reserved_1[20]; /* 0x24 -- 0x37 */ + u32 intreg; /* 0x38 */ + u32 intmask; /* 0x3c */ + u32 macaddr0hi; /* 0x40 */ + u32 macaddr0lo; /* 0x44 */ +}; + +struct eth_dma_regs { + u32 busmode; /* 0x00 */ + u32 txpolldemand; /* 0x04 */ + u32 rxpolldemand; /* 0x08 */ + u32 rxdesclistaddr; /* 0x0c */ + u32 txdesclistaddr; /* 0x10 */ + u32 status; /* 0x14 */ + u32 opmode; /* 0x18 */ + u32 intenable; /* 0x1c */ + u8 reserved[40]; /* 0x20 -- 0x47 */ + u32 currhosttxdesc; /* 0x48 */ + u32 currhostrxdesc; /* 0x4c */ + u32 currhosttxbuffaddr; /* 0x50 */ + u32 currhostrxbuffaddr; /* 0x54 */ +}; + +void gmac_reset(void); +void gmacsec_reset(void); +void ipq_gmac_common_init(ipq_gmac_board_cfg_t *cfg); +int ipq_gmac_init(ipq_gmac_board_cfg_t *cfg); + +enum DmaDescriptorStatus { /* status word of DMA descriptor */ + DescOwnByDma = 0x80000000, /* (OWN)Descriptor is owned by DMA engine 31 RW */ + + DescDAFilterFail = 0x40000000, /* (AFM)Rx - DA Filter Fail for the rx frame 30 */ + + DescFrameLengthMask = 0x3FFF0000, /* (FL)Receive descriptor frame length 29:16 */ + DescFrameLengthShift = 16, + + DescError = 0x00008000, /* (ES)Error summary bit - OR of the follo. bits: 15 */ + /* DE || OE || IPC || LC || RWT || RE || CE */ + DescRxTruncated = 0x00004000, /* (DE)Rx - no more descriptors for receive frame 14 */ + DescSAFilterFail = 0x00002000, /* (SAF)Rx - SA Filter Fail for the received frame 13 */ + DescRxLengthError = 0x00001000, /* (LE)Rx - frm size not matching with len field 12 */ + DescRxDamaged = 0x00000800, /* (OE)Rx - frm was damaged due to buffer overflow 11 */ + DescRxVLANTag = 0x00000400, /* (VLAN)Rx - received frame is a VLAN frame 10 */ + DescRxFirst = 0x00000200, /* (FS)Rx - first descriptor of the frame 9 */ + DescRxLast = 0x00000100, /* (LS)Rx - last descriptor of the frame 8 */ + DescRxLongFrame = 0x00000080, /* (Giant Frame)Rx - frame is longer than 1518/1522 7 */ + DescRxCollision = 0x00000040, /* (LC)Rx - late collision occurred during reception 6 */ + DescRxFrameEther = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ + DescRxWatchdog = 0x00000010, /* (RWT)Rx - watchdog timer expired during reception 4 */ + DescRxMiiError = 0x00000008, /* (RE)Rx - error reported by MII interface 3 */ + DescRxDribbling = 0x00000004, /* (DE)Rx - frame contains non int multiple of 8 bits 2 */ + DescRxCrc = 0x00000002, /* (CE)Rx - CRC error 1 */ + + DescRxEXTsts = 0x00000001, /* Extended Status Available (RDES4) 0 */ + + DescTxIntEnable = 0x40000000, /* (IC)Tx - interrupt on completion 30 */ + DescTxLast = 0x20000000, /* (LS)Tx - Last segment of the frame 29 */ + DescTxFirst = 0x10000000, /* (FS)Tx - First segment of the frame 28 */ + DescTxDisableCrc = 0x08000000, /* (DC)Tx - Add CRC disabled (first segment only) 27 */ + DescTxDisablePadd = 0x04000000, /* (DP)disable padding, added by - reyaz 26 */ + + DescTxCisMask = 0x00c00000, /* Tx checksum offloading control mask 23:22 */ + DescTxCisBypass = 0x00000000, /* Checksum bypass */ + DescTxCisIpv4HdrCs = 0x00400000, /* IPv4 header checksum */ + DescTxCisTcpOnlyCs = 0x00800000, /* TCP/UDP/ICMP checksum. Pseudo header checksum is assumed to be present*/ + DescTxCisTcpPseudoCs = 0x00c00000, /* TCP/UDP/ICMP checksum fully in hardware including pseudo header */ + + TxDescEndOfRing = 0x00200000, /* (TER)End of descriptors ring 21 */ + TxDescChain = 0x00100000, /* (TCH)Second buffer address is chain address 20 */ + + DescRxChkBit0 = 0x00000001, /* () Rx - Rx Payload Checksum Error 0 */ + DescRxChkBit7 = 0x00000080, /* (IPC CS ERROR)Rx - Ipv4 header checksum error 7 */ + DescRxChkBit5 = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ + + DescRxTSavail = 0x00000080, /* Time stamp available 7 */ + DescRxFrameType = 0x00000020, /* (FT)Rx - Frame type - Ethernet, otherwise 802.3 5 */ + + DescTxIpv4ChkError = 0x00010000, /* (IHE) Tx Ip header error 16 */ + DescTxTimeout = 0x00004000, /* (JT)Tx - Transmit jabber timeout 14 */ + DescTxFrameFlushed = 0x00002000, /* (FF)Tx - DMA/MTL flushed the frame due to SW flush 13 */ + DescTxPayChkError = 0x00001000, /* (PCE) Tx Payload checksum Error 12 */ + DescTxLostCarrier = 0x00000800, /* (LC)Tx - carrier lost during tramsmission 11 */ + DescTxNoCarrier = 0x00000400, /* (NC)Tx - no carrier signal from the tranceiver 10 */ + DescTxLateCollision = 0x00000200, /* (LC)Tx - transmission aborted due to collision 9 */ + DescTxExcCollisions = 0x00000100, /* (EC)Tx - transmission aborted after 16 collisions 8 */ + DescTxVLANFrame = 0x00000080, /* (VF)Tx - VLAN-type frame 7 */ + + DescTxCollMask = 0x00000078, /* (CC)Tx - Collision count 6:3 */ + DescTxCollShift = 3, + + DescTxExcDeferral = 0x00000004, /* (ED)Tx - excessive deferral 2 */ + DescTxUnderflow = 0x00000002, /* (UF)Tx - late data arrival from the memory 1 */ + DescTxDeferred = 0x00000001, /* (DB)Tx - frame transmision deferred 0 */ + + /* + * This explains the RDES1/TDES1 bits layout + * ------------------------------------------------------------------------ + * RDES1/TDES1 | Control Bits | Byte Count Buffer 2 | Byte Count Buffer 1 | + * ------------------------------------------------------------------------ + */ + /* DmaDescriptorLength length word of DMA descriptor */ + + + RxDisIntCompl = 0x80000000, /* (Disable Rx int on completion) 31 */ + RxDescEndOfRing = 0x00008000, /* (TER)End of descriptors ring 15 */ + RxDescChain = 0x00004000, /* (TCH)Second buffer address is chain address 14 */ + + /* DescSize2Mask = 0x1FFF0000, */ /* (TBS2) Buffer 2 size 28:16 */ + /* DescSize2Shift = 16, */ + DescSize1Mask = 0x00001FFF, /* (TBS1) Buffer 1 size 12:0 */ + DescSize1Shift = 0, + + + /* + * This explains the RDES4 Extended Status bits layout + * ---------------------------------------------------------------------- + * RDES4 | Extended Status | + * ---------------------------------------------------------------------- + */ + DescRxPtpAvail = 0x00004000, /* PTP snapshot available 14 */ + DescRxPtpVer = 0x00002000, /* When set indicates IEEE1584 Version 2 (else Ver1) 13 */ + DescRxPtpFrameType = 0x00001000, /* PTP frame type Indicates PTP sent over ethernet 12 */ + DescRxPtpMessageType = 0x00000F00, /* Message Type 11:8 */ + DescRxPtpNo = 0x00000000, /* 0000 => No PTP message received */ + DescRxPtpSync = 0x00000100, /* 0001 => Sync (all clock types) received */ + DescRxPtpFollowUp = 0x00000200, /* 0010 => Follow_Up (all clock types) received */ + DescRxPtpDelayReq = 0x00000300, /* 0011 => Delay_Req (all clock types) received */ + DescRxPtpDelayResp = 0x00000400, /* 0100 => Delay_Resp (all clock types) received */ + DescRxPtpPdelayReq = 0x00000500, /* 0101 => Pdelay_Req (in P to P tras clk) or Announce in Ord and Bound clk */ + DescRxPtpPdelayResp = 0x00000600, /* 0110 => Pdealy_Resp(in P to P trans clk) or Management in Ord and Bound clk */ + DescRxPtpPdelayRespFP = 0x00000700, /* 0111 => Pdealy_Resp_Follow_Up (in P to P trans clk) or Signaling in Ord and Bound clk */ + DescRxPtpIPV6 = 0x00000080, /* Received Packet is in IPV6 Packet 7 */ + DescRxPtpIPV4 = 0x00000040, /* Received Packet is in IPV4 Packet 6 */ + + DescRxChkSumBypass = 0x00000020, /* When set indicates checksum offload engine 5 + * is bypassed */ + DescRxIpPayloadError = 0x00000010, /* When set indicates 16bit IP payload CS is in error 4 */ + DescRxIpHeaderError = 0x00000008, /* When set indicates 16bit IPV4 header CS is in 3 + * error or IP datagram version is not consistent + * with Ethernet type value */ + DescRxIpPayloadType = 0x00000007, /* Indicate the type of payload encapsulated 2:0 + * in IPdatagram processed by COE (Rx) */ + DescRxIpPayloadUnknown = 0x00000000, /* Unknown or didnot process IP payload */ + DescRxIpPayloadUDP = 0x00000001, /* UDP */ + DescRxIpPayloadTCP = 0x00000002, /* TCP */ + DescRxIpPayloadICMP = 0x00000003, /* ICMP */ + +}; + +/********************************************************** + * GMAC DMA registers + * For Pci based system address is BARx + GmaDmaBase + * For any other system translation is done accordingly + **********************************************************/ + +enum DmaRegisters +{ + DmaBusMode = 0x0000, /* CSR0 - Bus Mode Register */ + DmaTxPollDemand = 0x0004, /* CSR1 - Transmit Poll Demand Register */ + DmaRxPollDemand = 0x0008, /* CSR2 - Receive Poll Demand Register */ + DmaRxBaseAddr = 0x000C, /* CSR3 - Receive Descriptor list base address */ + DmaTxBaseAddr = 0x0010, /* CSR4 - Transmit Descriptor list base address */ + DmaStatus = 0x0014, /* CSR5 - Dma status Register */ + DmaControl = 0x0018, /* CSR6 - Dma Operation Mode Register */ + DmaInterrupt = 0x001C, /* CSR7 - Interrupt enable */ + DmaMissedFr = 0x0020, /* CSR8 - Missed Frame & Buffer overflow Counter*/ + DmaTxCurrDesc = 0x0048, /* - Current host Tx Desc Register */ + DmaRxCurrDesc = 0x004C, /* - Current host Rx Desc Register */ + DmaTxCurrAddr = 0x0050, /* CSR20- Current host transmit buffer address */ + DmaRxCurrAddr = 0x0054, /* CSR21- Current host receive buffer address */ +}; + +/********************************************************** + * DMA Engine registers Layout + **********************************************************/ + +/* DmaBusMode = 0x0000, CSR0 - Bus Mode */ +enum DmaBusModeReg +{ /* Bit description Bits R/W Reset value */ + DmaFixedBurstEnable = 0x00010000, /* (FB)Fixed Burst SINGLE, INCR4, INCR8 or INCR16 16 RW */ + DmaFixedBurstDisable = 0x00000000, /* SINGLE, INCR 0 */ + DmaTxPriority = 0x08000000, + + DmaTxPriorityRatio11 = 0x00000000, /* (PR)TX:RX DMA priority ratio 1:1 15:14 RW 00 */ + DmaTxPriorityRatio21 = 0x00004000, /* (PR)TX:RX DMA priority ratio 2:1 */ + DmaTxPriorityRatio31 = 0x00008000, /* (PR)TX:RX DMA priority ratio 3:1 */ + DmaTxPriorityRatio41 = 0x0000C000, /* (PR)TX:RX DMA priority ratio 4:1 */ + + DmaBurstLengthx8 = 0x01000000, /* When set mutiplies the PBL by 8 24 RW 0 */ + + DmaBurstLength256 = 0x01002000, /*(DmaBurstLengthx8 | DmaBurstLength32) = 256 [24] 13:8 */ + DmaBurstLength128 = 0x01001000, /*(DmaBurstLengthx8 | DmaBurstLength16) = 128 [24] 13:8 */ + DmaBurstLength64 = 0x01000800, /*(DmaBurstLengthx8 | DmaBurstLength8) = 64 [24] 13:8 */ + DmaBurstLength32 = 0x00002000, /* (PBL) programmable Dma burst length = 32 13:8 RW */ + DmaBurstLength16 = 0x00001000, /* Dma burst length = 16 */ + DmaBurstLength8 = 0x00000800, /* Dma burst length = 8 */ + DmaBurstLength4 = 0x00000400, /* Dma burst length = 4 */ + DmaBurstLength2 = 0x00000200, /* Dma burst length = 2 */ + DmaBurstLength1 = 0x00000100, /* Dma burst length = 1 */ + DmaBurstLength0 = 0x00000000, /* Dma burst length = 0 00 */ + + DmaDescriptor8Words = 0x00000080, /* Enh Descriptor works 1 => 8 word descriptor 7 0 */ + DmaDescriptor4Words = 0x00000000, /* Enh Descriptor works 0 => 4 word descriptor 7 0 */ + + DmaDescriptorSkip16 = 0x00000040, /* (DSL)Descriptor skip length (no.of dwords) 6:2 RW */ + DmaDescriptorSkip8 = 0x00000020, /* between two unchained descriptors */ + DmaDescriptorSkip4 = 0x00000010, + DmaDescriptorSkip2 = 0x00000008, + DmaDescriptorSkip1 = 0x00000004, + DmaDescriptorSkip0 = 0x00000000, + + DmaArbitRr = 0x00000000, /* (DA) DMA RR arbitration 1 RW 0 */ + DmaArbitPr = 0x00000002, /* Rx has priority over Tx */ + + DmaResetOn = 0x00000001, /* (SWR)Software Reset DMA engine 0 RW */ + DmaResetOff = 0x00000000, /* 0 */ +}; + +/* DmaStatus = 0x0014, CSR5 - Dma status Register */ +enum DmaStatusReg +{ + /* Bit 28 27 and 26 indicate whether the interrupt due to PMT GMACMMC or GMAC LINE Remaining bits are DMA interrupts */ + GmacPmtIntr = 0x10000000, /* (GPI)Gmac subsystem interrupt 28 RO 0 */ + GmacMmcIntr = 0x08000000, /* (GMI)Gmac MMC subsystem interrupt 27 RO 0 */ + GmacLineIntfIntr = 0x04000000, /* Line interface interrupt 26 RO 0 */ + + DmaErrorBit2 = 0x02000000, /* (EB)Error bits 0-data buffer, 1-desc. access 25 RO 0 */ + DmaErrorBit1 = 0x01000000, /* (EB)Error bits 0-write trnsf, 1-read transfr 24 RO 0 */ + DmaErrorBit0 = 0x00800000, /* (EB)Error bits 0-Rx DMA, 1-Tx DMA 23 RO 0 */ + + DmaTxState = 0x00700000, /* (TS)Transmit process state 22:20 RO */ + DmaTxStopped = 0x00000000, /* Stopped - Reset or Stop Tx Command issued 000 */ + DmaTxFetching = 0x00100000, /* Running - fetching the Tx descriptor */ + DmaTxWaiting = 0x00200000, /* Running - waiting for status */ + DmaTxReading = 0x00300000, /* Running - reading the data from host memory */ + DmaTxSuspended = 0x00600000, /* Suspended - Tx Descriptor unavailabe */ + DmaTxClosing = 0x00700000, /* Running - closing Rx descriptor */ + + DmaRxState = 0x000E0000, /* (RS)Receive process state 19:17 RO */ + DmaRxStopped = 0x00000000, /* Stopped - Reset or Stop Rx Command issued 000 */ + DmaRxFetching = 0x00020000, /* Running - fetching the Rx descriptor */ + DmaRxWaiting = 0x00060000, /* Running - waiting for packet */ + DmaRxSuspended = 0x00080000, /* Suspended - Rx Descriptor unavailable */ + DmaRxClosing = 0x000A0000, /* Running - closing descriptor */ + DmaRxQueuing = 0x000E0000, /* Running - queuing the recieve frame into host memory */ + + DmaIntNormal = 0x00010000, /* (NIS)Normal interrupt summary 16 RW 0 */ + DmaIntAbnormal = 0x00008000, /* (AIS)Abnormal interrupt summary 15 RW 0 */ + + DmaIntEarlyRx = 0x00004000, /* Early receive interrupt (Normal) RW 0 */ + DmaIntBusError = 0x00002000, /* Fatal bus error (Abnormal) RW 0 */ + DmaIntEarlyTx = 0x00000400, /* Early transmit interrupt (Abnormal) RW 0 */ + DmaIntRxWdogTO = 0x00000200, /* Receive Watchdog Timeout (Abnormal) RW 0 */ + DmaIntRxStopped = 0x00000100, /* Receive process stopped (Abnormal) RW 0 */ + DmaIntRxNoBuffer = 0x00000080, /* Receive buffer unavailable (Abnormal) RW 0 */ + DmaIntRxCompleted = 0x00000040, /* Completion of frame reception (Normal) RW 0 */ + DmaIntTxUnderflow = 0x00000020, /* Transmit underflow (Abnormal) RW 0 */ + DmaIntRcvOverflow = 0x00000010, /* Receive Buffer overflow interrupt RW 0 */ + DmaIntTxJabberTO = 0x00000008, /* Transmit Jabber Timeout (Abnormal) RW 0 */ + DmaIntTxNoBuffer = 0x00000004, /* Transmit buffer unavailable (Normal) RW 0 */ + DmaIntTxStopped = 0x00000002, /* Transmit process stopped (Abnormal) RW 0 */ + DmaIntTxCompleted = 0x00000001, /* Transmit completed (Normal) RW 0 */ +}; + +/* DmaControl = 0x0018, CSR6 - Dma Operation Mode Register */ +enum DmaControlReg +{ + DmaDisableDropTcpCs = 0x04000000, /* (DT) Dis. drop. of tcp/ip CS error frames 26 RW 0 */ + + DmaStoreAndForward = 0x00200000, /* (SF)Store and forward 21 RW 0 */ + DmaFlushTxFifo = 0x00100000, /* (FTF)Tx FIFO controller is reset to default 20 RW 0 */ + + DmaTxThreshCtrl = 0x0001C000, /* (TTC)Controls thre Threh of MTL tx Fifo 16:14 RW */ + DmaTxThreshCtrl16 = 0x0001C000, /* (TTC)Controls thre Threh of MTL tx Fifo 16 16:14 RW */ + DmaTxThreshCtrl24 = 0x00018000, /* (TTC)Controls thre Threh of MTL tx Fifo 24 16:14 RW */ + DmaTxThreshCtrl32 = 0x00014000, /* (TTC)Controls thre Threh of MTL tx Fifo 32 16:14 RW */ + DmaTxThreshCtrl40 = 0x00010000, /* (TTC)Controls thre Threh of MTL tx Fifo 40 16:14 RW */ + DmaTxThreshCtrl256 = 0x0000c000, /* (TTC)Controls thre Threh of MTL tx Fifo 256 16:14 RW */ + DmaTxThreshCtrl192 = 0x00008000, /* (TTC)Controls thre Threh of MTL tx Fifo 192 16:14 RW */ + DmaTxThreshCtrl128 = 0x00004000, /* (TTC)Controls thre Threh of MTL tx Fifo 128 16:14 RW */ + DmaTxThreshCtrl64 = 0x00000000, /* (TTC)Controls thre Threh of MTL tx Fifo 64 16:14 RW 000 */ + + DmaTxStart = 0x00002000, /* (ST)Start/Stop transmission 13 RW 0 */ + + DmaRxFlowCtrlDeact = 0x00401800, /* (RFD)Rx flow control deact. threhold [22] 12:11 RW */ + DmaRxFlowCtrlDeact1K = 0x00000000, /* (RFD)Rx flow control deact. threhold (1kbytes) [22] 12:11 RW 00 */ + DmaRxFlowCtrlDeact2K = 0x00000800, /* (RFD)Rx flow control deact. threhold (2kbytes) [22] 12:11 RW */ + DmaRxFlowCtrlDeact3K = 0x00001000, /* (RFD)Rx flow control deact. threhold (3kbytes) [22] 12:11 RW */ + DmaRxFlowCtrlDeact4K = 0x00001800, /* (RFD)Rx flow control deact. threhold (4kbytes) [22] 12:11 RW */ + DmaRxFlowCtrlDeact5K = 0x00400000, /* (RFD)Rx flow control deact. threhold (4kbytes) [22] 12:11 RW */ + DmaRxFlowCtrlDeact6K = 0x00400800, /* (RFD)Rx flow control deact. threhold (4kbytes) [22] 12:11 RW */ + DmaRxFlowCtrlDeact7K = 0x00401000, /* (RFD)Rx flow control deact. threhold (4kbytes) [22] 12:11 RW */ + + DmaRxFlowCtrlAct = 0x00800600, /* (RFA)Rx flow control Act. threshold [23] 10:09 RW */ + DmaRxFlowCtrlAct1K = 0x00000000, /* (RFA)Rx flow control Act. threshold (1kbytes) [23] 10:09 RW 00 */ + DmaRxFlowCtrlAct2K = 0x00000200, /* (RFA)Rx flow control Act. threshold (2kbytes) [23] 10:09 RW */ + DmaRxFlowCtrlAct3K = 0x00000400, /* (RFA)Rx flow control Act. threshold (3kbytes) [23] 10:09 RW */ + DmaRxFlowCtrlAct4K = 0x00000600, /* (RFA)Rx flow control Act. threshold (4kbytes) [23] 10:09 RW */ + DmaRxFlowCtrlAct5K = 0x00800000, /* (RFA)Rx flow control Act. threshold (5kbytes) [23] 10:09 RW */ + DmaRxFlowCtrlAct6K = 0x00800200, /* (RFA)Rx flow control Act. threshold (6kbytes) [23] 10:09 RW */ + DmaRxFlowCtrlAct7K = 0x00800400, /* (RFA)Rx flow control Act. threshold (7kbytes) [23] 10:09 RW */ + + DmaRxThreshCtrl = 0x00000018, /* (RTC)Controls thre Threh of MTL rx Fifo 4:3 RW */ + DmaRxThreshCtrl64 = 0x00000000, /* (RTC)Controls thre Threh of MTL tx Fifo 64 4:3 RW */ + DmaRxThreshCtrl32 = 0x00000008, /* (RTC)Controls thre Threh of MTL tx Fifo 32 4:3 RW */ + DmaRxThreshCtrl96 = 0x00000010, /* (RTC)Controls thre Threh of MTL tx Fifo 96 4:3 RW */ + DmaRxThreshCtrl128 = 0x00000018, /* (RTC)Controls thre Threh of MTL tx Fifo 128 4:3 RW */ + + DmaEnHwFlowCtrl = 0x00000100, /* (EFC)Enable HW flow control 8 RW */ + DmaDisHwFlowCtrl = 0x00000000, /* Disable HW flow control 0 */ + + DmaFwdErrorFrames = 0x00000080, /* (FEF)Forward error frames 7 RW 0 */ + DmaFwdUnderSzFrames = 0x00000040, /* (FUF)Forward undersize frames 6 RW 0 */ + DmaTxSecondFrame = 0x00000004, /* (OSF)Operate on second frame 4 RW 0 */ + DmaRxStart = 0x00000002, /* (SR)Start/Stop reception 1 RW 0 */ +}; + +/* GmacFlowControl = 0x0018, Flow control Register Layout */ +enum GmacFlowControlReg +{ + GmacPauseTimeMask = 0xFFFF0000, /* (PT) PAUSE TIME field in the control frame 31:16 RW 0000 */ + GmacPauseTimeShift = 16, + DmaDisableFlushRxFrames = 0x01000000, + + GmacPauseLowThresh = 0x00000030, + GmacPauseLowThresh3 = 0x00000030, /* (PLT)thresh for pause tmr 256 slot time 5:4 RW */ + GmacPauseLowThresh2 = 0x00000020, /* 144 slot time */ + GmacPauseLowThresh1 = 0x00000010, /* 28 slot time */ + GmacPauseLowThresh0 = 0x00000000, /* 4 slot time 000 */ + + GmacUnicastPauseFrame = 0x00000008, + GmacUnicastPauseFrameOn = 0x00000008, /* (UP)Detect pause frame with unicast addr. 3 RW */ + GmacUnicastPauseFrameOff = 0x00000000, /* Detect only pause frame with multicast addr. 0 */ + + GmacRxFlowControl = 0x00000004, + GmacRxFlowControlEnable = 0x00000004, /* (RFE)Enable Rx flow control 2 RW */ + GmacRxFlowControlDisable = 0x00000000, /* Disable Rx flow control 0 */ + + GmacTxFlowControl = 0x00000002, + GmacTxFlowControlEnable = 0x00000002, /* (TFE)Enable Tx flow control 1 RW */ + GmacTxFlowControlDisable = 0x00000000, /* Disable flow control 0 */ + + GmacFlowControlBackPressure = 0x00000001, + GmacSendPauseFrame = 0x00000001, /* (FCB/PBA)send pause frm/Apply back pressure 0 RW 0 */ +}; + +#endif + diff --git a/board/qca/arm/ipq5018/ipq5018.c b/board/qca/arm/ipq5018/ipq5018.c index 141e0929de..f06276c593 100644 --- a/board/qca/arm/ipq5018/ipq5018.c +++ b/board/qca/arm/ipq5018/ipq5018.c @@ -16,7 +16,7 @@ #include #include #include - +#include #include #include #include @@ -28,6 +28,9 @@ #define DLOAD_MAGIC_COOKIE 0x10 #define DLOAD_DISABLED 0x40 + +ipq_gmac_board_cfg_t gmac_cfg[CONFIG_IPQ_NO_MACS]; + DECLARE_GLOBAL_DATA_PTR; struct sdhci_host mmc_host; extern int ipq_spi_init(u16); @@ -542,3 +545,46 @@ unsigned long timer_read_counter(void) return 0; } +int board_eth_init(bd_t *bis) +{ + int status; + int gmac_gpio_node = 0; + int gmac_cfg_node = 0, offset = 0; + int loop = 0; + int phy_name_len = 0; + char *phy_name_ptr = NULL; + + gmac_cfg_node = fdt_path_offset(gd->fdt_blob, "/gmac_cfg"); + if (gmac_cfg_node >= 0) { + for (offset = fdt_first_subnode(gd->fdt_blob, gmac_cfg_node); + offset > 0; + offset = fdt_next_subnode(gd->fdt_blob, offset) , loop++) { + + gmac_cfg[loop].base = fdtdec_get_uint(gd->fdt_blob, + offset, "base", 0); + + gmac_cfg[loop].unit = fdtdec_get_uint(gd->fdt_blob, + offset, "unit", 0); + + gmac_cfg[loop].phy_addr = fdtdec_get_uint(gd->fdt_blob, + offset, "phy_address", 0); + + phy_name_ptr = (char*)fdt_getprop(gd->fdt_blob, offset, + "phy_name", &phy_name_len); + + strlcpy((char *)gmac_cfg[loop].phy_name, phy_name_ptr, phy_name_len); + } + } + gmac_cfg[loop].unit = -1; + + ipq_gmac_common_init(gmac_cfg); + + gmac_gpio_node = fdt_path_offset(gd->fdt_blob, "gmac_gpio"); + if (gmac_gpio_node) { + qca_gpio_init(gmac_gpio_node); + } + status = ipq_gmac_init(gmac_cfg); + + return status; +} + diff --git a/board/qca/arm/ipq5018/ipq5018.h b/board/qca/arm/ipq5018/ipq5018.h index bc8c9fb3e3..dd6f59544d 100644 --- a/board/qca/arm/ipq5018/ipq5018.h +++ b/board/qca/arm/ipq5018/ipq5018.h @@ -17,6 +17,7 @@ #include #include #include +#include "phy.h" #define MSM_SDC1_BASE 0x7800000 #define MSM_SDC1_SDHCI_BASE 0x7804000 @@ -95,6 +96,30 @@ unsigned int __invoke_psci_fn_smc(unsigned int, unsigned int, unsigned int, unsigned int); + +typedef struct { + uint base; + int unit; + uint phy_addr; + const char phy_name[MDIO_NAME_LEN]; +} ipq_gmac_board_cfg_t; + +extern ipq_gmac_board_cfg_t gmac_cfg[]; + +static inline int gmac_cfg_is_valid(ipq_gmac_board_cfg_t *cfg) +{ + /* + * 'cfg' is valid if and only if + * unit number is non-negative and less than CONFIG_IPQ_NO_MACS. + */ + return ((cfg >= &gmac_cfg[0]) && + (cfg < &gmac_cfg[CONFIG_IPQ_NO_MACS]) && + (cfg->unit >= 0) && (cfg->unit < CONFIG_IPQ_NO_MACS)); +} + +extern void ipq_gmac_common_init(ipq_gmac_board_cfg_t *cfg); +extern int ipq_gmac_init(ipq_gmac_board_cfg_t *cfg); + struct smem_ram_ptn { char name[16]; unsigned long long start; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index b2f469e954..3270843d63 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -86,6 +86,7 @@ obj-$(CONFIG_IPQ807X_EDMA) += ipq807x/ipq807x_uniphy.o obj-$(CONFIG_IPQ6018_EDMA) += ipq6018/ipq6018_edma.o obj-$(CONFIG_IPQ6018_EDMA) += ipq6018/ipq6018_ppe.o obj-$(CONFIG_IPQ6018_EDMA) += ipq6018/ipq6018_uniphy.o +obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/ipq5018_gmac.o obj-$(CONFIG_IPQ_MDIO) += ipq_common/ipq_mdio.o obj-$(CONFIG_QCA8075_PHY) += ipq_common/ipq_qca8075.o obj-$(CONFIG_QCA8033_PHY) += ipq_common/ipq_qca8033.o diff --git a/drivers/net/ipq5018/ipq5018_gmac.c b/drivers/net/ipq5018/ipq5018_gmac.c new file mode 100644 index 0000000000..0c4ef71fc2 --- /dev/null +++ b/drivers/net/ipq5018/ipq5018_gmac.c @@ -0,0 +1,607 @@ +/* +* Copyright (c) 2019 The Linux Foundation. All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ipq_phy.h" +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define ipq_info printf +#define ipq_dbg printf +#define DESC_SIZE (sizeof(ipq_gmac_desc_t)) +#define DESC_FLUSH_SIZE (((DESC_SIZE + (CONFIG_SYS_CACHELINE_SIZE - 1)) \ + / CONFIG_SYS_CACHELINE_SIZE) * \ + (CONFIG_SYS_CACHELINE_SIZE)) + +static struct ipq_eth_dev *ipq_gmac_macs[IPQ5018_GMAC_PORT]; + +uchar ipq_def_enetaddr[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; +phy_info_t *phy_info[IPQ5018_PHY_MAX] = {0}; + +extern int ipq_mdio_read(int mii_id, int regnum, ushort *data); +extern int ipq_qca8033_phy_init(struct phy_ops **ops, u32 phy_id); +extern void ipq_qca8075_phy_map_ops(struct phy_ops **ops); +extern int ipq_qca8081_phy_init(struct phy_ops **ops, u32 phy_id); +extern int ipq_sw_mdio_init(const char *); + +static int ipq_eth_wr_macaddr(struct eth_device *dev) +{ + struct ipq_eth_dev *priv = dev->priv; + struct eth_mac_regs *mac_p = (struct eth_mac_regs *)priv->mac_regs_p; + u32 macid_lo, macid_hi; + u8 *mac_id = &dev->enetaddr[0]; + + macid_lo = mac_id[0] + (mac_id[1] << 8) + + (mac_id[2] << 16) + (mac_id[3] << 24); + macid_hi = mac_id[4] + (mac_id[5] << 8); + + writel(macid_hi, &mac_p->macaddr0hi); + writel(macid_lo, &mac_p->macaddr0lo); + + return 0; +} + +static void ipq_mac_reset(struct eth_device *dev) +{ + struct ipq_eth_dev *priv = dev->priv; + struct eth_dma_regs *dma_reg = (struct eth_dma_regs *)priv->dma_regs_p; + u32 val; + + writel(DMAMAC_SRST, &dma_reg->busmode); + do { + udelay(10); + val = readl(&dma_reg->busmode); + } while (val & DMAMAC_SRST); + +} + +static void ipq_eth_mac_cfg(struct eth_device *dev) +{ + struct ipq_eth_dev *priv = dev->priv; + struct eth_mac_regs *mac_reg = (struct eth_mac_regs *)priv->mac_regs_p; + + uint ipq_mac_cfg = 0; + uint ipq_mac_framefilter = 0; + + ipq_mac_framefilter = PROMISCUOUS_MODE_ON; + + ipq_mac_cfg |= (FRAME_BURST_ENABLE | JUMBO_FRAME_ENABLE | + TX_ENABLE | RX_ENABLE | FULL_DUPLEX_ENABLE); + + writel(ipq_mac_cfg, &mac_reg->conf); + writel(ipq_mac_framefilter, &mac_reg->framefilt); +} + +static void ipq_eth_dma_cfg(struct eth_device *dev) +{ + struct ipq_eth_dev *priv = dev->priv; + struct eth_dma_regs *dma_reg = (struct eth_dma_regs *)priv->dma_regs_p; + uint ipq_dma_bus_mode; + uint ipq_dma_op_mode; + + ipq_dma_op_mode = DmaStoreAndForward | DmaRxThreshCtrl128 | + DmaTxSecondFrame; + ipq_dma_bus_mode = DmaFixedBurstEnable | DmaBurstLength16 | + DmaDescriptorSkip0 | DmaDescriptor8Words | + DmaArbitPr; + + writel(ipq_dma_bus_mode, &dma_reg->busmode); + writel(ipq_dma_op_mode, &dma_reg->opmode); +} + +static void ipq_eth_flw_cntl_cfg(struct eth_device *dev) +{ + struct ipq_eth_dev *priv = dev->priv; + struct eth_mac_regs *mac_reg = (struct eth_mac_regs *)priv->mac_regs_p; + struct eth_dma_regs *dma_reg = (struct eth_dma_regs *)priv->dma_regs_p; + uint ipq_dma_flw_cntl; + uint ipq_mac_flw_cntl; + + ipq_dma_flw_cntl = DmaRxFlowCtrlAct3K | DmaRxFlowCtrlDeact4K | + DmaEnHwFlowCtrl; + ipq_mac_flw_cntl = GmacRxFlowControl | GmacTxFlowControl | 0xFFFF0000; + + setbits_le32(&dma_reg->opmode, ipq_dma_flw_cntl); + setbits_le32(&mac_reg->flowcontrol, ipq_mac_flw_cntl); +} + +static int ipq_gmac_alloc_fifo(int ndesc, ipq_gmac_desc_t **fifo) +{ + int i; + void *addr; + + addr = memalign((CONFIG_SYS_CACHELINE_SIZE), + (ndesc * DESC_FLUSH_SIZE)); + + for (i = 0; i < ndesc; i++) { + fifo[i] = (ipq_gmac_desc_t *)((unsigned long)addr + + (i * DESC_FLUSH_SIZE)); + if (fifo[i] == NULL) { + ipq_info("Can't allocate desc fifos\n"); + return -1; + } + } + return 0; +} + +static int ipq_gmac_rx_desc_setup(struct ipq_eth_dev *priv) +{ + struct eth_dma_regs *dma_reg = (struct eth_dma_regs *)priv->dma_regs_p; + ipq_gmac_desc_t *rxdesc; + int i; + + for (i = 0; i < NO_OF_RX_DESC; i++) { + rxdesc = priv->desc_rx[i]; + rxdesc->length |= ((ETH_MAX_FRAME_LEN << DescSize1Shift) & + DescSize1Mask); + rxdesc->buffer1 = virt_to_phys(net_rx_packets[i]); + rxdesc->data1 = (unsigned long)priv->desc_rx[(i + 1) % + NO_OF_RX_DESC]; + + rxdesc->extstatus = 0; + rxdesc->reserved1 = 0; + rxdesc->timestamplow = 0; + rxdesc->timestamphigh = 0; + rxdesc->status = DescOwnByDma; + + + flush_dcache_range((unsigned long)rxdesc, + (unsigned long)rxdesc + DESC_SIZE); + + } + /* Assign Descriptor base address to dmadesclist addr reg */ + writel((uint)priv->desc_rx[0], &dma_reg->rxdesclistaddr); + + return 0; +} + +static int ipq_gmac_tx_rx_desc_ring(struct ipq_eth_dev *priv) +{ + int i; + ipq_gmac_desc_t *desc; + + if (ipq_gmac_alloc_fifo(NO_OF_TX_DESC, priv->desc_tx)) + return -1; + + for (i = 0; i < NO_OF_TX_DESC; i++) { + desc = priv->desc_tx[i]; + memset(desc, 0, DESC_SIZE); + + desc->status = + (i == (NO_OF_TX_DESC - 1)) ? TxDescEndOfRing : 0; + + desc->status |= TxDescChain; + + desc->data1 = (unsigned long)priv->desc_tx[(i + 1) % + NO_OF_TX_DESC ]; + + flush_dcache_range((unsigned long)desc, + (unsigned long)desc + DESC_SIZE); + + } + + if (ipq_gmac_alloc_fifo(NO_OF_RX_DESC, priv->desc_rx)) + return -1; + + for (i = 0; i < NO_OF_RX_DESC; i++) { + desc = priv->desc_rx[i]; + memset(desc, 0, DESC_SIZE); + desc->length = + (i == (NO_OF_RX_DESC - 1)) ? RxDescEndOfRing : 0; + desc->length |= RxDescChain; + + desc->data1 = (unsigned long)priv->desc_rx[(i + 1) % + NO_OF_RX_DESC]; + + flush_dcache_range((unsigned long)desc, + (unsigned long)desc + DESC_SIZE); + + } + + priv->next_tx = 0; + priv->next_rx = 0; + + return 0; +} + +static inline void ipq_gmac_give_to_dma(ipq_gmac_desc_t *fr) +{ + fr->status |= DescOwnByDma; +} + +static inline u32 ipq_gmac_owned_by_dma(ipq_gmac_desc_t *fr) +{ + return (fr->status & DescOwnByDma); +} + +static inline u32 ipq_gmac_is_desc_empty(ipq_gmac_desc_t *fr) +{ + return ((fr->length & DescSize1Mask) == 0); +} +#if 0 +static int ipq_eth_update(struct eth_device *dev, bd_t *this) +{ + struct ipq_eth_dev *priv = dev->priv; + struct phy_ops *phy_get_ops = priv->ops[priv->mac_unit]; + uint phy_status; + uint cur_speed; + uint cur_duplex; + + phy_status = phy_get_ops->phy_get_link_status(priv->mac_unit, priv->phy_address); + phy_get_ops->phy_get_speed(priv->mac_unit, priv->phy_address, &curr_speed); + phy_get_ops->phy_get_duplex(priv->mac_unit, priv->phy_address, &duplex); + + if (cur_speed != priv->speed || cur_duplex != priv->duplex) { + ipq_info("Link %x status changed\n", priv->mac_unit); + if (priv->duplex) + ipq_info("Full duplex link\n"); + else + ipq_info("Half duplex link\n"); + + ipq_info("Link %x up, Phy_status = %x\n", + priv->mac_unit, phy_status); + + switch (cur_speed) { + case SPEED_1000M: + ipq_info("Port:%d speed 1000Mbps\n", + priv->mac_unit); + priv->mac_ps = GMII_PORT_SELECT; + break; + + case SPEED_100M: + ipq_info("Port:%d speed 100Mbps\n", + priv->mac_unit); + priv->mac_ps = MII_PORT_SELECT; + break; + + case SPEED_10M: + ipq_info("Port:%d speed 10Mbps\n", + priv->mac_unit); + priv->mac_ps = MII_PORT_SELECT; + break; + + default: + ipq_info("Port speed unknown\n"); + return -1; + } + + priv->speed = cur_speed; + priv->duplex = cur_duplex; + + } + + return 0; +} +#endif +int ipq_eth_init(struct eth_device *dev, bd_t *this) +{ + struct ipq_eth_dev *priv = dev->priv; + struct eth_dma_regs *dma_reg = (struct eth_dma_regs *)priv->dma_regs_p; + u32 data; +#if 0 + ipq_phy_link_status(dev); +#endif + priv->next_rx = 0; + priv->next_tx = 0; + + ipq_mac_reset(dev); + ipq_eth_wr_macaddr(dev); + + /* DMA, MAC configuration for Synopsys GMAC */ + ipq_eth_dma_cfg(dev); + ipq_eth_mac_cfg(dev); + ipq_eth_flw_cntl_cfg(dev); + + /* clear all pending interrupts if any */ + data = readl(&dma_reg->status); + writel(data, &dma_reg->status); + + /* Setup Rx fifos and assign base address to */ + ipq_gmac_rx_desc_setup(priv); + + writel((uint)priv->desc_tx[0], &dma_reg->txdesclistaddr); + setbits_le32(&dma_reg->opmode, (RXSTART)); + setbits_le32(&dma_reg->opmode, (TXSTART)); + + return 1; +} + +static int ipq_eth_send(struct eth_device *dev, void *packet, int length) +{ + struct ipq_eth_dev *priv = dev->priv; + struct eth_dma_regs *dma_p = (struct eth_dma_regs *)priv->dma_regs_p; + ipq_gmac_desc_t *txdesc = priv->desc_tx[priv->next_tx]; + int i; + + invalidate_dcache_range((unsigned long)txdesc, + (unsigned long)txdesc + DESC_FLUSH_SIZE); + + /* Check if the dma descriptor is still owned by DMA */ + if (ipq_gmac_owned_by_dma(txdesc)) { + ipq_info("BUG: Tx descriptor is owned by DMA %p\n", txdesc); + return NETDEV_TX_BUSY; + } + + txdesc->length |= ((length <status |= (DescTxFirst | DescTxLast | DescTxIntEnable); + txdesc->buffer1 = virt_to_phys(packet); + ipq_gmac_give_to_dma(txdesc); + + flush_dcache_range((unsigned long)txdesc, + (unsigned long)txdesc + DESC_SIZE); + + flush_dcache_range((unsigned long)(txdesc->buffer1), + (unsigned long)(txdesc->buffer1) + PKTSIZE_ALIGN); + + /* Start the transmission */ + writel(POLL_DATA, &dma_p->txpolldemand); + + for (i = 0; i < MAX_WAIT; i++) { + + udelay(10); + + invalidate_dcache_range((unsigned long)txdesc, + (unsigned long)txdesc + DESC_FLUSH_SIZE); + + if (!ipq_gmac_owned_by_dma(txdesc)) + break; + } + + if (i == MAX_WAIT) { + ipq_info("Tx Timed out\n"); + } + + /* reset the descriptors */ + txdesc->status = (priv->next_tx == (NO_OF_TX_DESC - 1)) ? + TxDescEndOfRing : 0; + txdesc->status |= TxDescChain; + txdesc->length = 0; + txdesc->buffer1 = 0; + + priv->next_tx = (priv->next_tx + 1) % NO_OF_TX_DESC; + + txdesc->data1 = (unsigned long)priv->desc_tx[priv->next_tx]; + + + flush_dcache_range((unsigned long)txdesc, + (unsigned long)txdesc + DESC_SIZE); + + return 0; +} + +static int ipq_eth_recv(struct eth_device *dev) +{ + struct ipq_eth_dev *priv = dev->priv; + struct eth_dma_regs *dma_p = (struct eth_dma_regs *)priv->dma_regs_p; + int length = 0; + ipq_gmac_desc_t *rxdesc = priv->desc_rx[priv->next_rx]; + uint status; + + invalidate_dcache_range((unsigned long)(priv->desc_rx[0]), + (unsigned long)(priv->desc_rx[NO_OF_RX_DESC - 1]) + + DESC_FLUSH_SIZE); + + for (rxdesc = priv->desc_rx[priv->next_rx]; + !ipq_gmac_owned_by_dma(rxdesc); + rxdesc = priv->desc_rx[priv->next_rx]) { + + status = rxdesc->status; + length = ((status & DescFrameLengthMask) >> + DescFrameLengthShift); + + invalidate_dcache_range( + (unsigned long)(net_rx_packets[priv->next_rx]), + (unsigned long)(net_rx_packets[priv->next_rx]) + + PKTSIZE_ALIGN); + net_process_received_packet(net_rx_packets[priv->next_rx], length - 4); + + rxdesc->length = ((ETH_MAX_FRAME_LEN << DescSize1Shift) & + DescSize1Mask); + + rxdesc->length |= (priv->next_rx == (NO_OF_RX_DESC - 1)) ? + RxDescEndOfRing : 0; + rxdesc->length |= RxDescChain; + + rxdesc->buffer1 = virt_to_phys(net_rx_packets[priv->next_rx]); + + priv->next_rx = (priv->next_rx + 1) % NO_OF_RX_DESC; + + rxdesc->data1 = (unsigned long)priv->desc_rx[priv->next_rx]; + + rxdesc->extstatus = 0; + rxdesc->reserved1 = 0; + rxdesc->timestamplow = 0; + rxdesc->timestamphigh = 0; + rxdesc->status = DescOwnByDma; + + flush_dcache_range((unsigned long)rxdesc, + (unsigned long)rxdesc + DESC_SIZE); + + writel(POLL_DATA, &dma_p->rxpolldemand); + } + + return length; +} + +static void ipq_eth_halt(struct eth_device *dev) +{ + if (dev->state != ETH_STATE_ACTIVE) + return; + /* reset the mac */ + ipq_mac_reset(dev); +} + +int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg) +{ + struct eth_device *dev[CONFIG_IPQ_NO_MACS]; + uchar enet_addr[CONFIG_IPQ_NO_MACS * 6]; + char ethaddr[32] = "ethaddr"; + int i, phy_id; + uint32_t phy_chip_id, phy_chip_id1, phy_chip_id2; + int ret; + memset(enet_addr, 0, sizeof(enet_addr)); + + /* Getting the MAC address from ART partition */ + ret = get_eth_mac_address(enet_addr, CONFIG_IPQ_NO_MACS); + + for (i = 0; gmac_cfg_is_valid(gmac_cfg); gmac_cfg++, i++) { + + dev[i] = malloc(sizeof(struct eth_device)); + if (dev[i] == NULL) + goto failed; + + ipq_gmac_macs[i] = malloc(sizeof(struct ipq_eth_dev)); + if (ipq_gmac_macs[i] == NULL) + goto failed; + + memset(dev[i], 0, sizeof(struct eth_device)); + memset(ipq_gmac_macs[i], 0, sizeof(struct ipq_eth_dev)); + + dev[i]->iobase = gmac_cfg->base; + dev[i]->init = ipq_eth_init; + dev[i]->halt = ipq_eth_halt; + dev[i]->recv = ipq_eth_recv; + dev[i]->send = ipq_eth_send; + dev[i]->write_hwaddr = ipq_eth_wr_macaddr; + dev[i]->priv = (void *) ipq_gmac_macs[i]; + + snprintf(dev[i]->name, sizeof(dev[i]->name), "eth%d", i); + + /* + * Setting the Default MAC address if the MAC read from ART partition + * is invalid. + */ + if ((ret < 0) || + (!is_valid_ethaddr(&enet_addr[i * 6]))) { + memcpy(&dev[i]->enetaddr[0], ipq_def_enetaddr, 6); + dev[i]->enetaddr[5] = dev[i]->enetaddr[5] + i; + } else { + memcpy(&dev[i]->enetaddr[0], &enet_addr[i * 6], 6); + } + + ipq_info("MAC%x addr:%x:%x:%x:%x:%x:%x\n", + gmac_cfg->unit, dev[i]->enetaddr[0], + dev[i]->enetaddr[1], + dev[i]->enetaddr[2], + dev[i]->enetaddr[3], + dev[i]->enetaddr[4], + dev[i]->enetaddr[5]); + + snprintf(ethaddr, sizeof(ethaddr), "eth%daddr", (i + 1)); + + ipq_gmac_macs[i]->dev = dev[i]; + ipq_gmac_macs[i]->mac_unit = gmac_cfg->unit; + ipq_gmac_macs[i]->mac_regs_p = + (struct eth_mac_regs *)(gmac_cfg->base); + ipq_gmac_macs[i]->dma_regs_p = + (struct eth_dma_regs *)(gmac_cfg->base + DW_DMA_BASE_OFFSET); +#if 0 + ipq_gmac_macs[i]->interface = gmac_cfg->phy; + ipq_gmac_macs[i]->phy_address = gmac_cfg->phy_addr.addr; + ipq_gmac_macs[i]->no_of_phys = gmac_cfg->phy_addr.count; +#endif + ipq_gmac_macs[i]->phy_address = gmac_cfg->phy_addr; + ipq_gmac_macs[i]->gmac_board_cfg = gmac_cfg; + +#if 0 + if (get_params.gmac_port == gmac_cfg->unit) { + ipq_gmac_macs[i]->forced_params = &get_params; + } +#endif + /* tx/rx Descriptor initialization */ + if (ipq_gmac_tx_rx_desc_ring(dev[i]->priv) == -1) + goto failed; +#if 0 + if(ipq_gmac_macs[i]->mac_unit == 0) + ipq_gmac_macs[i]->speed = SPEED_10M; + else + ipq_gmac_macs[i]->speed = SPEED_1000M; +#endif + + strlcpy((char *)ipq_gmac_macs[i]->phy_name, gmac_cfg->phy_name, + sizeof(ipq_gmac_macs[i]->phy_name)); + +if (0){ + if (ipq_sw_mdio_init(gmac_cfg->phy_name)) + goto failed; + + for (phy_id = 0; phy_id < 2; phy_id++) { +#if 0 + if (phy_node >= 0) { + phy_addr = phy_info[phy_id]->phy_address; + } else { + if (phy_id == port_8033) + phy_addr = QCA8033_PHY_ADDR; + else if (phy_id == aquantia_port) + phy_addr = AQU_PHY_ADDR; + else + phy_addr = phy_id; + } +#endif + phy_chip_id1 = ipq_mdio_read( + ipq_gmac_macs[i]->phy_address, QCA_PHY_ID1, NULL); + phy_chip_id2 = ipq_mdio_read( + ipq_gmac_macs[i]->phy_address, QCA_PHY_ID2, NULL); + phy_chip_id = (phy_chip_id1 << 16) | phy_chip_id2; + + switch(phy_chip_id) { + case QCA8033_PHY: + ipq_qca8033_phy_init( + &ipq_gmac_macs[i]->ops[phy_id], + ipq_gmac_macs[i]->phy_address); + break; + case QCA8081_PHY: + case QCA8081_1_1_PHY: + ipq_qca8081_phy_init( + &ipq_gmac_macs[i]->ops[phy_id], + ipq_gmac_macs[i]->phy_address); + break; + default: + ipq_qca8075_phy_map_ops(&ipq_gmac_macs[i]->ops[phy_id]); + break; + } + } +} + eth_register(dev[i]); + } + + return 0; + +failed: + for (i = 0; i < IPQ5018_GMAC_PORT; i++) { + if (dev[i]) { + eth_unregister(dev[i]); + free(dev[i]); + } + if (ipq_gmac_macs[i]) + free(ipq_gmac_macs[i]); + } + + return -ENOMEM; +} + +void ipq_gmac_common_init(ipq_gmac_board_cfg_t *gmac_cfg) +{ + return; +} + diff --git a/include/configs/ipq5018.h b/include/configs/ipq5018.h index bf30362e20..96013db3fd 100644 --- a/include/configs/ipq5018.h +++ b/include/configs/ipq5018.h @@ -93,7 +93,6 @@ #define CONFIG_QCA_SMEM_BASE 0x4AB00000 #define CONFIG_IPQ_FDT_HIGH 0x4A400000 -#define CONFIG_IPQ_NO_MACS 6 #define CONFIG_ENV_IS_IN_SPI_FLASH 1 #define CONFIG_ENV_SECT_SIZE (64 * 1024) @@ -195,6 +194,28 @@ extern loff_t board_env_size; #define CONFIG_CMD_I2C #define CONFIG_DM_I2C #endif + +/* +* GMAC Enable +*/ + +#define CONFIG_IPQ5018_GMAC + +#define CONFIG_NET_RETRY_COUNT 5 +#define CONFIG_SYS_RX_ETH_BUFFER 16 +#define CONFIG_CMD_PING +#define CONFIG_CMD_DHCP +#define CONFIG_MII +#define CONFIG_CMD_MII +#define CONFIG_IPADDR 192.168.10.10 +#define CONFIG_NETMASK 255.255.255.0 +#define CONFIG_SERVERIP 192.168.10.19 +#define CONFIG_CMD_TFTPPUT +#define CONFIG_IPQ_MDIO 2 +#define CONFIG_IPQ_ETH_INIT_DEFER + +#define CONFIG_IPQ_NO_MACS 2 + /* * Expose SPI driver as a pseudo NAND driver to make use * of U-Boot's MTD framework.