1799e125cSJiandong Zheng /* 2*5c624b9eSSuji Velupillai * Copyright 2014-2017 Broadcom. 3799e125cSJiandong Zheng * 4799e125cSJiandong Zheng * SPDX-License-Identifier: GPL-2.0+ 5799e125cSJiandong Zheng */ 6799e125cSJiandong Zheng 7799e125cSJiandong Zheng #ifdef BCM_GMAC_DEBUG 8799e125cSJiandong Zheng #ifndef DEBUG 9799e125cSJiandong Zheng #define DEBUG 10799e125cSJiandong Zheng #endif 11799e125cSJiandong Zheng #endif 12799e125cSJiandong Zheng 13799e125cSJiandong Zheng #include <config.h> 14799e125cSJiandong Zheng #include <common.h> 15799e125cSJiandong Zheng #include <malloc.h> 16799e125cSJiandong Zheng #include <net.h> 17799e125cSJiandong Zheng #include <asm/io.h> 18799e125cSJiandong Zheng #include <phy.h> 19799e125cSJiandong Zheng 20799e125cSJiandong Zheng #include "bcm-sf2-eth.h" 21799e125cSJiandong Zheng #include "bcm-sf2-eth-gmac.h" 22799e125cSJiandong Zheng 23799e125cSJiandong Zheng #define SPINWAIT(exp, us) { \ 24799e125cSJiandong Zheng uint countdown = (us) + 9; \ 25799e125cSJiandong Zheng while ((exp) && (countdown >= 10)) {\ 26799e125cSJiandong Zheng udelay(10); \ 27799e125cSJiandong Zheng countdown -= 10; \ 28799e125cSJiandong Zheng } \ 29799e125cSJiandong Zheng } 30799e125cSJiandong Zheng 31*5c624b9eSSuji Velupillai #define RX_BUF_SIZE_ALIGNED ALIGN(RX_BUF_SIZE, ARCH_DMA_MINALIGN) 32*5c624b9eSSuji Velupillai #define TX_BUF_SIZE_ALIGNED ALIGN(TX_BUF_SIZE, ARCH_DMA_MINALIGN) 33*5c624b9eSSuji Velupillai #define DESCP_SIZE_ALIGNED ALIGN(sizeof(dma64dd_t), ARCH_DMA_MINALIGN) 34*5c624b9eSSuji Velupillai 35799e125cSJiandong Zheng static int gmac_disable_dma(struct eth_dma *dma, int dir); 36799e125cSJiandong Zheng static int gmac_enable_dma(struct eth_dma *dma, int dir); 37799e125cSJiandong Zheng 38799e125cSJiandong Zheng /* DMA Descriptor */ 39799e125cSJiandong Zheng typedef struct { 40799e125cSJiandong Zheng /* misc control bits */ 41799e125cSJiandong Zheng uint32_t ctrl1; 42799e125cSJiandong Zheng /* buffer count and address extension */ 43799e125cSJiandong Zheng uint32_t ctrl2; 44799e125cSJiandong Zheng /* memory address of the date buffer, bits 31:0 */ 45799e125cSJiandong Zheng uint32_t addrlow; 46799e125cSJiandong Zheng /* memory address of the date buffer, bits 63:32 */ 47799e125cSJiandong Zheng uint32_t addrhigh; 48799e125cSJiandong Zheng } dma64dd_t; 49799e125cSJiandong Zheng 50799e125cSJiandong Zheng uint32_t g_dmactrlflags; 51799e125cSJiandong Zheng 52799e125cSJiandong Zheng static uint32_t dma_ctrlflags(uint32_t mask, uint32_t flags) 53799e125cSJiandong Zheng { 54799e125cSJiandong Zheng debug("%s enter\n", __func__); 55799e125cSJiandong Zheng 56799e125cSJiandong Zheng g_dmactrlflags &= ~mask; 57799e125cSJiandong Zheng g_dmactrlflags |= flags; 58799e125cSJiandong Zheng 59799e125cSJiandong Zheng /* If trying to enable parity, check if parity is actually supported */ 60799e125cSJiandong Zheng if (g_dmactrlflags & DMA_CTRL_PEN) { 61799e125cSJiandong Zheng uint32_t control; 62799e125cSJiandong Zheng 63799e125cSJiandong Zheng control = readl(GMAC0_DMA_TX_CTRL_ADDR); 64799e125cSJiandong Zheng writel(control | D64_XC_PD, GMAC0_DMA_TX_CTRL_ADDR); 65799e125cSJiandong Zheng if (readl(GMAC0_DMA_TX_CTRL_ADDR) & D64_XC_PD) { 66799e125cSJiandong Zheng /* 67799e125cSJiandong Zheng * We *can* disable it, therefore it is supported; 68799e125cSJiandong Zheng * restore control register 69799e125cSJiandong Zheng */ 70799e125cSJiandong Zheng writel(control, GMAC0_DMA_TX_CTRL_ADDR); 71799e125cSJiandong Zheng } else { 72799e125cSJiandong Zheng /* Not supported, don't allow it to be enabled */ 73799e125cSJiandong Zheng g_dmactrlflags &= ~DMA_CTRL_PEN; 74799e125cSJiandong Zheng } 75799e125cSJiandong Zheng } 76799e125cSJiandong Zheng 77799e125cSJiandong Zheng return g_dmactrlflags; 78799e125cSJiandong Zheng } 79799e125cSJiandong Zheng 80799e125cSJiandong Zheng static inline void reg32_clear_bits(uint32_t reg, uint32_t value) 81799e125cSJiandong Zheng { 82799e125cSJiandong Zheng uint32_t v = readl(reg); 83799e125cSJiandong Zheng v &= ~(value); 84799e125cSJiandong Zheng writel(v, reg); 85799e125cSJiandong Zheng } 86799e125cSJiandong Zheng 87799e125cSJiandong Zheng static inline void reg32_set_bits(uint32_t reg, uint32_t value) 88799e125cSJiandong Zheng { 89799e125cSJiandong Zheng uint32_t v = readl(reg); 90799e125cSJiandong Zheng v |= value; 91799e125cSJiandong Zheng writel(v, reg); 92799e125cSJiandong Zheng } 93799e125cSJiandong Zheng 94799e125cSJiandong Zheng #ifdef BCM_GMAC_DEBUG 95799e125cSJiandong Zheng static void dma_tx_dump(struct eth_dma *dma) 96799e125cSJiandong Zheng { 97799e125cSJiandong Zheng dma64dd_t *descp = NULL; 98799e125cSJiandong Zheng uint8_t *bufp; 99799e125cSJiandong Zheng int i; 100799e125cSJiandong Zheng 101799e125cSJiandong Zheng printf("TX DMA Register:\n"); 102799e125cSJiandong Zheng printf("control:0x%x; ptr:0x%x; addrl:0x%x; addrh:0x%x; stat0:0x%x, stat1:0x%x\n", 103799e125cSJiandong Zheng readl(GMAC0_DMA_TX_CTRL_ADDR), 104799e125cSJiandong Zheng readl(GMAC0_DMA_TX_PTR_ADDR), 105799e125cSJiandong Zheng readl(GMAC0_DMA_TX_ADDR_LOW_ADDR), 106799e125cSJiandong Zheng readl(GMAC0_DMA_TX_ADDR_HIGH_ADDR), 107799e125cSJiandong Zheng readl(GMAC0_DMA_TX_STATUS0_ADDR), 108799e125cSJiandong Zheng readl(GMAC0_DMA_TX_STATUS1_ADDR)); 109799e125cSJiandong Zheng 110799e125cSJiandong Zheng printf("TX Descriptors:\n"); 111799e125cSJiandong Zheng for (i = 0; i < TX_BUF_NUM; i++) { 112799e125cSJiandong Zheng descp = (dma64dd_t *)(dma->tx_desc_aligned) + i; 113799e125cSJiandong Zheng printf("ctrl1:0x%08x; ctrl2:0x%08x; addr:0x%x 0x%08x\n", 114799e125cSJiandong Zheng descp->ctrl1, descp->ctrl2, 115799e125cSJiandong Zheng descp->addrhigh, descp->addrlow); 116799e125cSJiandong Zheng } 117799e125cSJiandong Zheng 118799e125cSJiandong Zheng printf("TX Buffers:\n"); 119799e125cSJiandong Zheng /* Initialize TX DMA descriptor table */ 120799e125cSJiandong Zheng for (i = 0; i < TX_BUF_NUM; i++) { 121*5c624b9eSSuji Velupillai bufp = (uint8_t *)(dma->tx_buf + i * TX_BUF_SIZE_ALIGNED); 122799e125cSJiandong Zheng printf("buf%d:0x%x; ", i, (uint32_t)bufp); 123799e125cSJiandong Zheng } 124799e125cSJiandong Zheng printf("\n"); 125799e125cSJiandong Zheng } 126799e125cSJiandong Zheng 127799e125cSJiandong Zheng static void dma_rx_dump(struct eth_dma *dma) 128799e125cSJiandong Zheng { 129799e125cSJiandong Zheng dma64dd_t *descp = NULL; 130799e125cSJiandong Zheng uint8_t *bufp; 131799e125cSJiandong Zheng int i; 132799e125cSJiandong Zheng 133799e125cSJiandong Zheng printf("RX DMA Register:\n"); 134799e125cSJiandong Zheng printf("control:0x%x; ptr:0x%x; addrl:0x%x; addrh:0x%x; stat0:0x%x, stat1:0x%x\n", 135799e125cSJiandong Zheng readl(GMAC0_DMA_RX_CTRL_ADDR), 136799e125cSJiandong Zheng readl(GMAC0_DMA_RX_PTR_ADDR), 137799e125cSJiandong Zheng readl(GMAC0_DMA_RX_ADDR_LOW_ADDR), 138799e125cSJiandong Zheng readl(GMAC0_DMA_RX_ADDR_HIGH_ADDR), 139799e125cSJiandong Zheng readl(GMAC0_DMA_RX_STATUS0_ADDR), 140799e125cSJiandong Zheng readl(GMAC0_DMA_RX_STATUS1_ADDR)); 141799e125cSJiandong Zheng 142799e125cSJiandong Zheng printf("RX Descriptors:\n"); 143799e125cSJiandong Zheng for (i = 0; i < RX_BUF_NUM; i++) { 144799e125cSJiandong Zheng descp = (dma64dd_t *)(dma->rx_desc_aligned) + i; 145799e125cSJiandong Zheng printf("ctrl1:0x%08x; ctrl2:0x%08x; addr:0x%x 0x%08x\n", 146799e125cSJiandong Zheng descp->ctrl1, descp->ctrl2, 147799e125cSJiandong Zheng descp->addrhigh, descp->addrlow); 148799e125cSJiandong Zheng } 149799e125cSJiandong Zheng 150799e125cSJiandong Zheng printf("RX Buffers:\n"); 151799e125cSJiandong Zheng for (i = 0; i < RX_BUF_NUM; i++) { 152*5c624b9eSSuji Velupillai bufp = dma->rx_buf + i * RX_BUF_SIZE_ALIGNED; 153799e125cSJiandong Zheng printf("buf%d:0x%x; ", i, (uint32_t)bufp); 154799e125cSJiandong Zheng } 155799e125cSJiandong Zheng printf("\n"); 156799e125cSJiandong Zheng } 157799e125cSJiandong Zheng #endif 158799e125cSJiandong Zheng 159799e125cSJiandong Zheng static int dma_tx_init(struct eth_dma *dma) 160799e125cSJiandong Zheng { 161799e125cSJiandong Zheng dma64dd_t *descp = NULL; 162799e125cSJiandong Zheng uint8_t *bufp; 163799e125cSJiandong Zheng int i; 164799e125cSJiandong Zheng uint32_t ctrl; 165799e125cSJiandong Zheng 166799e125cSJiandong Zheng debug("%s enter\n", __func__); 167799e125cSJiandong Zheng 168799e125cSJiandong Zheng /* clear descriptor memory */ 169799e125cSJiandong Zheng memset((void *)(dma->tx_desc_aligned), 0, 170*5c624b9eSSuji Velupillai TX_BUF_NUM * DESCP_SIZE_ALIGNED); 171*5c624b9eSSuji Velupillai memset(dma->tx_buf, 0, TX_BUF_NUM * TX_BUF_SIZE_ALIGNED); 172799e125cSJiandong Zheng 173799e125cSJiandong Zheng /* Initialize TX DMA descriptor table */ 174799e125cSJiandong Zheng for (i = 0; i < TX_BUF_NUM; i++) { 175799e125cSJiandong Zheng descp = (dma64dd_t *)(dma->tx_desc_aligned) + i; 176*5c624b9eSSuji Velupillai bufp = dma->tx_buf + i * TX_BUF_SIZE_ALIGNED; 177799e125cSJiandong Zheng /* clear buffer memory */ 178*5c624b9eSSuji Velupillai memset((void *)bufp, 0, TX_BUF_SIZE_ALIGNED); 179799e125cSJiandong Zheng 180799e125cSJiandong Zheng ctrl = 0; 181799e125cSJiandong Zheng /* if last descr set endOfTable */ 182799e125cSJiandong Zheng if (i == (TX_BUF_NUM-1)) 183799e125cSJiandong Zheng ctrl = D64_CTRL1_EOT; 184799e125cSJiandong Zheng descp->ctrl1 = ctrl; 185799e125cSJiandong Zheng descp->ctrl2 = 0; 186799e125cSJiandong Zheng descp->addrlow = (uint32_t)bufp; 187799e125cSJiandong Zheng descp->addrhigh = 0; 188799e125cSJiandong Zheng } 189799e125cSJiandong Zheng 190799e125cSJiandong Zheng /* flush descriptor and buffer */ 191799e125cSJiandong Zheng descp = dma->tx_desc_aligned; 192799e125cSJiandong Zheng bufp = dma->tx_buf; 193799e125cSJiandong Zheng flush_dcache_range((unsigned long)descp, 194*5c624b9eSSuji Velupillai (unsigned long)descp + 195*5c624b9eSSuji Velupillai DESCP_SIZE_ALIGNED * TX_BUF_NUM); 196*5c624b9eSSuji Velupillai flush_dcache_range((unsigned long)bufp, 197*5c624b9eSSuji Velupillai (unsigned long)bufp + 198*5c624b9eSSuji Velupillai TX_BUF_SIZE_ALIGNED * TX_BUF_NUM); 199799e125cSJiandong Zheng 200799e125cSJiandong Zheng /* initialize the DMA channel */ 201799e125cSJiandong Zheng writel((uint32_t)(dma->tx_desc_aligned), GMAC0_DMA_TX_ADDR_LOW_ADDR); 202799e125cSJiandong Zheng writel(0, GMAC0_DMA_TX_ADDR_HIGH_ADDR); 203799e125cSJiandong Zheng 204799e125cSJiandong Zheng /* now update the dma last descriptor */ 205799e125cSJiandong Zheng writel(((uint32_t)(dma->tx_desc_aligned)) & D64_XP_LD_MASK, 206799e125cSJiandong Zheng GMAC0_DMA_TX_PTR_ADDR); 207799e125cSJiandong Zheng 208799e125cSJiandong Zheng return 0; 209799e125cSJiandong Zheng } 210799e125cSJiandong Zheng 211799e125cSJiandong Zheng static int dma_rx_init(struct eth_dma *dma) 212799e125cSJiandong Zheng { 213799e125cSJiandong Zheng uint32_t last_desc; 214799e125cSJiandong Zheng dma64dd_t *descp = NULL; 215799e125cSJiandong Zheng uint8_t *bufp; 216799e125cSJiandong Zheng uint32_t ctrl; 217799e125cSJiandong Zheng int i; 218799e125cSJiandong Zheng 219799e125cSJiandong Zheng debug("%s enter\n", __func__); 220799e125cSJiandong Zheng 221799e125cSJiandong Zheng /* clear descriptor memory */ 222799e125cSJiandong Zheng memset((void *)(dma->rx_desc_aligned), 0, 223*5c624b9eSSuji Velupillai RX_BUF_NUM * DESCP_SIZE_ALIGNED); 224799e125cSJiandong Zheng /* clear buffer memory */ 225*5c624b9eSSuji Velupillai memset(dma->rx_buf, 0, RX_BUF_NUM * RX_BUF_SIZE_ALIGNED); 226799e125cSJiandong Zheng 227799e125cSJiandong Zheng /* Initialize RX DMA descriptor table */ 228799e125cSJiandong Zheng for (i = 0; i < RX_BUF_NUM; i++) { 229799e125cSJiandong Zheng descp = (dma64dd_t *)(dma->rx_desc_aligned) + i; 230*5c624b9eSSuji Velupillai bufp = dma->rx_buf + i * RX_BUF_SIZE_ALIGNED; 231799e125cSJiandong Zheng ctrl = 0; 232799e125cSJiandong Zheng /* if last descr set endOfTable */ 233799e125cSJiandong Zheng if (i == (RX_BUF_NUM - 1)) 234799e125cSJiandong Zheng ctrl = D64_CTRL1_EOT; 235799e125cSJiandong Zheng descp->ctrl1 = ctrl; 236*5c624b9eSSuji Velupillai descp->ctrl2 = RX_BUF_SIZE_ALIGNED; 237799e125cSJiandong Zheng descp->addrlow = (uint32_t)bufp; 238799e125cSJiandong Zheng descp->addrhigh = 0; 239799e125cSJiandong Zheng 240799e125cSJiandong Zheng last_desc = ((uint32_t)(descp) & D64_XP_LD_MASK) 241799e125cSJiandong Zheng + sizeof(dma64dd_t); 242799e125cSJiandong Zheng } 243799e125cSJiandong Zheng 244799e125cSJiandong Zheng descp = dma->rx_desc_aligned; 245799e125cSJiandong Zheng bufp = dma->rx_buf; 246799e125cSJiandong Zheng /* flush descriptor and buffer */ 247799e125cSJiandong Zheng flush_dcache_range((unsigned long)descp, 248*5c624b9eSSuji Velupillai (unsigned long)descp + 249*5c624b9eSSuji Velupillai DESCP_SIZE_ALIGNED * RX_BUF_NUM); 250799e125cSJiandong Zheng flush_dcache_range((unsigned long)(bufp), 251*5c624b9eSSuji Velupillai (unsigned long)bufp + 252*5c624b9eSSuji Velupillai RX_BUF_SIZE_ALIGNED * RX_BUF_NUM); 253799e125cSJiandong Zheng 254799e125cSJiandong Zheng /* initailize the DMA channel */ 255799e125cSJiandong Zheng writel((uint32_t)descp, GMAC0_DMA_RX_ADDR_LOW_ADDR); 256799e125cSJiandong Zheng writel(0, GMAC0_DMA_RX_ADDR_HIGH_ADDR); 257799e125cSJiandong Zheng 258799e125cSJiandong Zheng /* now update the dma last descriptor */ 259799e125cSJiandong Zheng writel(last_desc, GMAC0_DMA_RX_PTR_ADDR); 260799e125cSJiandong Zheng 261799e125cSJiandong Zheng return 0; 262799e125cSJiandong Zheng } 263799e125cSJiandong Zheng 264799e125cSJiandong Zheng static int dma_init(struct eth_dma *dma) 265799e125cSJiandong Zheng { 266799e125cSJiandong Zheng debug(" %s enter\n", __func__); 267799e125cSJiandong Zheng 268799e125cSJiandong Zheng /* 269799e125cSJiandong Zheng * Default flags: For backwards compatibility both 270799e125cSJiandong Zheng * Rx Overflow Continue and Parity are DISABLED. 271799e125cSJiandong Zheng */ 272799e125cSJiandong Zheng dma_ctrlflags(DMA_CTRL_ROC | DMA_CTRL_PEN, 0); 273799e125cSJiandong Zheng 274799e125cSJiandong Zheng debug("rx burst len 0x%x\n", 275799e125cSJiandong Zheng (readl(GMAC0_DMA_RX_CTRL_ADDR) & D64_RC_BL_MASK) 276799e125cSJiandong Zheng >> D64_RC_BL_SHIFT); 277799e125cSJiandong Zheng debug("tx burst len 0x%x\n", 278799e125cSJiandong Zheng (readl(GMAC0_DMA_TX_CTRL_ADDR) & D64_XC_BL_MASK) 279799e125cSJiandong Zheng >> D64_XC_BL_SHIFT); 280799e125cSJiandong Zheng 281799e125cSJiandong Zheng dma_tx_init(dma); 282799e125cSJiandong Zheng dma_rx_init(dma); 283799e125cSJiandong Zheng 284799e125cSJiandong Zheng /* From end of chip_init() */ 285799e125cSJiandong Zheng /* enable the overflow continue feature and disable parity */ 286799e125cSJiandong Zheng dma_ctrlflags(DMA_CTRL_ROC | DMA_CTRL_PEN /* mask */, 287799e125cSJiandong Zheng DMA_CTRL_ROC /* value */); 288799e125cSJiandong Zheng 289799e125cSJiandong Zheng return 0; 290799e125cSJiandong Zheng } 291799e125cSJiandong Zheng 292799e125cSJiandong Zheng static int dma_deinit(struct eth_dma *dma) 293799e125cSJiandong Zheng { 294799e125cSJiandong Zheng debug(" %s enter\n", __func__); 295799e125cSJiandong Zheng 296799e125cSJiandong Zheng gmac_disable_dma(dma, MAC_DMA_RX); 297799e125cSJiandong Zheng gmac_disable_dma(dma, MAC_DMA_TX); 298799e125cSJiandong Zheng 299799e125cSJiandong Zheng free(dma->tx_buf); 300799e125cSJiandong Zheng dma->tx_buf = NULL; 301*5c624b9eSSuji Velupillai free(dma->tx_desc_aligned); 302799e125cSJiandong Zheng dma->tx_desc_aligned = NULL; 303799e125cSJiandong Zheng 304799e125cSJiandong Zheng free(dma->rx_buf); 305799e125cSJiandong Zheng dma->rx_buf = NULL; 306*5c624b9eSSuji Velupillai free(dma->rx_desc_aligned); 307799e125cSJiandong Zheng dma->rx_desc_aligned = NULL; 308799e125cSJiandong Zheng 309799e125cSJiandong Zheng return 0; 310799e125cSJiandong Zheng } 311799e125cSJiandong Zheng 312799e125cSJiandong Zheng int gmac_tx_packet(struct eth_dma *dma, void *packet, int length) 313799e125cSJiandong Zheng { 314*5c624b9eSSuji Velupillai uint8_t *bufp = dma->tx_buf + dma->cur_tx_index * TX_BUF_SIZE_ALIGNED; 315799e125cSJiandong Zheng 316799e125cSJiandong Zheng /* kick off the dma */ 317799e125cSJiandong Zheng size_t len = length; 318799e125cSJiandong Zheng int txout = dma->cur_tx_index; 319799e125cSJiandong Zheng uint32_t flags; 320799e125cSJiandong Zheng dma64dd_t *descp = NULL; 321799e125cSJiandong Zheng uint32_t ctrl; 322799e125cSJiandong Zheng uint32_t last_desc = (((uint32_t)dma->tx_desc_aligned) + 323799e125cSJiandong Zheng sizeof(dma64dd_t)) & D64_XP_LD_MASK; 324799e125cSJiandong Zheng size_t buflen; 325799e125cSJiandong Zheng 326799e125cSJiandong Zheng debug("%s enter\n", __func__); 327799e125cSJiandong Zheng 328799e125cSJiandong Zheng /* load the buffer */ 329799e125cSJiandong Zheng memcpy(bufp, packet, len); 330799e125cSJiandong Zheng 331799e125cSJiandong Zheng /* Add 4 bytes for Ethernet FCS/CRC */ 332799e125cSJiandong Zheng buflen = len + 4; 333799e125cSJiandong Zheng 334799e125cSJiandong Zheng ctrl = (buflen & D64_CTRL2_BC_MASK); 335799e125cSJiandong Zheng 336799e125cSJiandong Zheng /* the transmit will only be one frame or set SOF, EOF */ 337799e125cSJiandong Zheng /* also set int on completion */ 338799e125cSJiandong Zheng flags = D64_CTRL1_SOF | D64_CTRL1_IOC | D64_CTRL1_EOF; 339799e125cSJiandong Zheng 340799e125cSJiandong Zheng /* txout points to the descriptor to uset */ 341799e125cSJiandong Zheng /* if last descriptor then set EOT */ 342799e125cSJiandong Zheng if (txout == (TX_BUF_NUM - 1)) { 343799e125cSJiandong Zheng flags |= D64_CTRL1_EOT; 344799e125cSJiandong Zheng last_desc = ((uint32_t)(dma->tx_desc_aligned)) & D64_XP_LD_MASK; 345799e125cSJiandong Zheng } 346799e125cSJiandong Zheng 347799e125cSJiandong Zheng /* write the descriptor */ 348799e125cSJiandong Zheng descp = ((dma64dd_t *)(dma->tx_desc_aligned)) + txout; 349799e125cSJiandong Zheng descp->addrlow = (uint32_t)bufp; 350799e125cSJiandong Zheng descp->addrhigh = 0; 351799e125cSJiandong Zheng descp->ctrl1 = flags; 352799e125cSJiandong Zheng descp->ctrl2 = ctrl; 353799e125cSJiandong Zheng 354799e125cSJiandong Zheng /* flush descriptor and buffer */ 355*5c624b9eSSuji Velupillai flush_dcache_range((unsigned long)dma->tx_desc_aligned, 356*5c624b9eSSuji Velupillai (unsigned long)dma->tx_desc_aligned + 357*5c624b9eSSuji Velupillai DESCP_SIZE_ALIGNED * TX_BUF_NUM); 358799e125cSJiandong Zheng flush_dcache_range((unsigned long)bufp, 359*5c624b9eSSuji Velupillai (unsigned long)bufp + TX_BUF_SIZE_ALIGNED); 360799e125cSJiandong Zheng 361799e125cSJiandong Zheng /* now update the dma last descriptor */ 362799e125cSJiandong Zheng writel(last_desc, GMAC0_DMA_TX_PTR_ADDR); 363799e125cSJiandong Zheng 364799e125cSJiandong Zheng /* tx dma should be enabled so packet should go out */ 365799e125cSJiandong Zheng 366799e125cSJiandong Zheng /* update txout */ 367799e125cSJiandong Zheng dma->cur_tx_index = (txout + 1) & (TX_BUF_NUM - 1); 368799e125cSJiandong Zheng 369799e125cSJiandong Zheng return 0; 370799e125cSJiandong Zheng } 371799e125cSJiandong Zheng 372799e125cSJiandong Zheng bool gmac_check_tx_done(struct eth_dma *dma) 373799e125cSJiandong Zheng { 374799e125cSJiandong Zheng /* wait for tx to complete */ 375799e125cSJiandong Zheng uint32_t intstatus; 376799e125cSJiandong Zheng bool xfrdone = false; 377799e125cSJiandong Zheng 378799e125cSJiandong Zheng debug("%s enter\n", __func__); 379799e125cSJiandong Zheng 380799e125cSJiandong Zheng intstatus = readl(GMAC0_INT_STATUS_ADDR); 381799e125cSJiandong Zheng 382799e125cSJiandong Zheng debug("int(0x%x)\n", intstatus); 383799e125cSJiandong Zheng if (intstatus & (I_XI0 | I_XI1 | I_XI2 | I_XI3)) { 384799e125cSJiandong Zheng xfrdone = true; 385799e125cSJiandong Zheng /* clear the int bits */ 386799e125cSJiandong Zheng intstatus &= ~(I_XI0 | I_XI1 | I_XI2 | I_XI3); 387799e125cSJiandong Zheng writel(intstatus, GMAC0_INT_STATUS_ADDR); 388799e125cSJiandong Zheng } else { 389799e125cSJiandong Zheng debug("Tx int(0x%x)\n", intstatus); 390799e125cSJiandong Zheng } 391799e125cSJiandong Zheng 392799e125cSJiandong Zheng return xfrdone; 393799e125cSJiandong Zheng } 394799e125cSJiandong Zheng 395799e125cSJiandong Zheng int gmac_check_rx_done(struct eth_dma *dma, uint8_t *buf) 396799e125cSJiandong Zheng { 397799e125cSJiandong Zheng void *bufp, *datap; 398799e125cSJiandong Zheng size_t rcvlen = 0, buflen = 0; 399799e125cSJiandong Zheng uint32_t stat0 = 0, stat1 = 0; 400799e125cSJiandong Zheng uint32_t control, offset; 401799e125cSJiandong Zheng uint8_t statbuf[HWRXOFF*2]; 402799e125cSJiandong Zheng 403799e125cSJiandong Zheng int index, curr, active; 404799e125cSJiandong Zheng dma64dd_t *descp = NULL; 405799e125cSJiandong Zheng 406799e125cSJiandong Zheng /* udelay(50); */ 407799e125cSJiandong Zheng 408799e125cSJiandong Zheng /* 409799e125cSJiandong Zheng * this api will check if a packet has been received. 410799e125cSJiandong Zheng * If so it will return the address of the buffer and current 411799e125cSJiandong Zheng * descriptor index will be incremented to the 412799e125cSJiandong Zheng * next descriptor. Once done with the frame the buffer should be 413799e125cSJiandong Zheng * added back onto the descriptor and the lastdscr should be updated 414799e125cSJiandong Zheng * to this descriptor. 415799e125cSJiandong Zheng */ 416799e125cSJiandong Zheng index = dma->cur_rx_index; 417799e125cSJiandong Zheng offset = (uint32_t)(dma->rx_desc_aligned); 418799e125cSJiandong Zheng stat0 = readl(GMAC0_DMA_RX_STATUS0_ADDR) & D64_RS0_CD_MASK; 419799e125cSJiandong Zheng stat1 = readl(GMAC0_DMA_RX_STATUS1_ADDR) & D64_RS0_CD_MASK; 420799e125cSJiandong Zheng curr = ((stat0 - offset) & D64_RS0_CD_MASK) / sizeof(dma64dd_t); 421799e125cSJiandong Zheng active = ((stat1 - offset) & D64_RS0_CD_MASK) / sizeof(dma64dd_t); 422799e125cSJiandong Zheng 423799e125cSJiandong Zheng /* check if any frame */ 424799e125cSJiandong Zheng if (index == curr) 425799e125cSJiandong Zheng return -1; 426799e125cSJiandong Zheng 427799e125cSJiandong Zheng debug("received packet\n"); 428799e125cSJiandong Zheng debug("expect(0x%x) curr(0x%x) active(0x%x)\n", index, curr, active); 429799e125cSJiandong Zheng /* remove warning */ 430799e125cSJiandong Zheng if (index == active) 431799e125cSJiandong Zheng ; 432799e125cSJiandong Zheng 433799e125cSJiandong Zheng /* get the packet pointer that corresponds to the rx descriptor */ 434*5c624b9eSSuji Velupillai bufp = dma->rx_buf + index * RX_BUF_SIZE_ALIGNED; 435799e125cSJiandong Zheng 436799e125cSJiandong Zheng descp = (dma64dd_t *)(dma->rx_desc_aligned) + index; 437799e125cSJiandong Zheng /* flush descriptor and buffer */ 438*5c624b9eSSuji Velupillai flush_dcache_range((unsigned long)dma->rx_desc_aligned, 439*5c624b9eSSuji Velupillai (unsigned long)dma->rx_desc_aligned + 440*5c624b9eSSuji Velupillai DESCP_SIZE_ALIGNED * RX_BUF_NUM); 441799e125cSJiandong Zheng flush_dcache_range((unsigned long)bufp, 442*5c624b9eSSuji Velupillai (unsigned long)bufp + RX_BUF_SIZE_ALIGNED); 443799e125cSJiandong Zheng 444799e125cSJiandong Zheng buflen = (descp->ctrl2 & D64_CTRL2_BC_MASK); 445799e125cSJiandong Zheng 446799e125cSJiandong Zheng stat0 = readl(GMAC0_DMA_RX_STATUS0_ADDR); 447799e125cSJiandong Zheng stat1 = readl(GMAC0_DMA_RX_STATUS1_ADDR); 448799e125cSJiandong Zheng 449799e125cSJiandong Zheng debug("bufp(0x%x) index(0x%x) buflen(0x%x) stat0(0x%x) stat1(0x%x)\n", 450799e125cSJiandong Zheng (uint32_t)bufp, index, buflen, stat0, stat1); 451799e125cSJiandong Zheng 452799e125cSJiandong Zheng dma->cur_rx_index = (index + 1) & (RX_BUF_NUM - 1); 453799e125cSJiandong Zheng 454799e125cSJiandong Zheng /* get buffer offset */ 455799e125cSJiandong Zheng control = readl(GMAC0_DMA_RX_CTRL_ADDR); 456799e125cSJiandong Zheng offset = (control & D64_RC_RO_MASK) >> D64_RC_RO_SHIFT; 457799e125cSJiandong Zheng rcvlen = *(uint16_t *)bufp; 458799e125cSJiandong Zheng 459799e125cSJiandong Zheng debug("Received %d bytes\n", rcvlen); 460799e125cSJiandong Zheng /* copy status into temp buf then copy data from rx buffer */ 461799e125cSJiandong Zheng memcpy(statbuf, bufp, offset); 462799e125cSJiandong Zheng datap = (void *)((uint32_t)bufp + offset); 463799e125cSJiandong Zheng memcpy(buf, datap, rcvlen); 464799e125cSJiandong Zheng 465799e125cSJiandong Zheng /* update descriptor that is being added back on ring */ 466*5c624b9eSSuji Velupillai descp->ctrl2 = RX_BUF_SIZE_ALIGNED; 467799e125cSJiandong Zheng descp->addrlow = (uint32_t)bufp; 468799e125cSJiandong Zheng descp->addrhigh = 0; 469799e125cSJiandong Zheng /* flush descriptor */ 470*5c624b9eSSuji Velupillai flush_dcache_range((unsigned long)dma->rx_desc_aligned, 471*5c624b9eSSuji Velupillai (unsigned long)dma->rx_desc_aligned + 472*5c624b9eSSuji Velupillai DESCP_SIZE_ALIGNED * RX_BUF_NUM); 473799e125cSJiandong Zheng 474799e125cSJiandong Zheng /* set the lastdscr for the rx ring */ 475799e125cSJiandong Zheng writel(((uint32_t)descp) & D64_XP_LD_MASK, GMAC0_DMA_RX_PTR_ADDR); 476799e125cSJiandong Zheng 477799e125cSJiandong Zheng return (int)rcvlen; 478799e125cSJiandong Zheng } 479799e125cSJiandong Zheng 480799e125cSJiandong Zheng static int gmac_disable_dma(struct eth_dma *dma, int dir) 481799e125cSJiandong Zheng { 482799e125cSJiandong Zheng int status; 483799e125cSJiandong Zheng 484799e125cSJiandong Zheng debug("%s enter\n", __func__); 485799e125cSJiandong Zheng 486799e125cSJiandong Zheng if (dir == MAC_DMA_TX) { 487799e125cSJiandong Zheng /* address PR8249/PR7577 issue */ 488799e125cSJiandong Zheng /* suspend tx DMA first */ 489799e125cSJiandong Zheng writel(D64_XC_SE, GMAC0_DMA_TX_CTRL_ADDR); 490799e125cSJiandong Zheng SPINWAIT(((status = (readl(GMAC0_DMA_TX_STATUS0_ADDR) & 491799e125cSJiandong Zheng D64_XS0_XS_MASK)) != 492799e125cSJiandong Zheng D64_XS0_XS_DISABLED) && 493799e125cSJiandong Zheng (status != D64_XS0_XS_IDLE) && 494799e125cSJiandong Zheng (status != D64_XS0_XS_STOPPED), 10000); 495799e125cSJiandong Zheng 496799e125cSJiandong Zheng /* 497799e125cSJiandong Zheng * PR2414 WAR: DMA engines are not disabled until 498799e125cSJiandong Zheng * transfer finishes 499799e125cSJiandong Zheng */ 500799e125cSJiandong Zheng writel(0, GMAC0_DMA_TX_CTRL_ADDR); 501799e125cSJiandong Zheng SPINWAIT(((status = (readl(GMAC0_DMA_TX_STATUS0_ADDR) & 502799e125cSJiandong Zheng D64_XS0_XS_MASK)) != 503799e125cSJiandong Zheng D64_XS0_XS_DISABLED), 10000); 504799e125cSJiandong Zheng 505799e125cSJiandong Zheng /* wait for the last transaction to complete */ 506799e125cSJiandong Zheng udelay(2); 507799e125cSJiandong Zheng 508799e125cSJiandong Zheng status = (status == D64_XS0_XS_DISABLED); 509799e125cSJiandong Zheng } else { 510799e125cSJiandong Zheng /* 511799e125cSJiandong Zheng * PR2414 WAR: DMA engines are not disabled until 512799e125cSJiandong Zheng * transfer finishes 513799e125cSJiandong Zheng */ 514799e125cSJiandong Zheng writel(0, GMAC0_DMA_RX_CTRL_ADDR); 515799e125cSJiandong Zheng SPINWAIT(((status = (readl(GMAC0_DMA_RX_STATUS0_ADDR) & 516799e125cSJiandong Zheng D64_RS0_RS_MASK)) != 517799e125cSJiandong Zheng D64_RS0_RS_DISABLED), 10000); 518799e125cSJiandong Zheng 519799e125cSJiandong Zheng status = (status == D64_RS0_RS_DISABLED); 520799e125cSJiandong Zheng } 521799e125cSJiandong Zheng 522799e125cSJiandong Zheng return status; 523799e125cSJiandong Zheng } 524799e125cSJiandong Zheng 525799e125cSJiandong Zheng static int gmac_enable_dma(struct eth_dma *dma, int dir) 526799e125cSJiandong Zheng { 527799e125cSJiandong Zheng uint32_t control; 528799e125cSJiandong Zheng 529799e125cSJiandong Zheng debug("%s enter\n", __func__); 530799e125cSJiandong Zheng 531799e125cSJiandong Zheng if (dir == MAC_DMA_TX) { 532799e125cSJiandong Zheng dma->cur_tx_index = 0; 533799e125cSJiandong Zheng 534799e125cSJiandong Zheng /* 535799e125cSJiandong Zheng * These bits 20:18 (burstLen) of control register can be 536799e125cSJiandong Zheng * written but will take effect only if these bits are 537799e125cSJiandong Zheng * valid. So this will not affect previous versions 538799e125cSJiandong Zheng * of the DMA. They will continue to have those bits set to 0. 539799e125cSJiandong Zheng */ 540799e125cSJiandong Zheng control = readl(GMAC0_DMA_TX_CTRL_ADDR); 541799e125cSJiandong Zheng 542799e125cSJiandong Zheng control |= D64_XC_XE; 543799e125cSJiandong Zheng if ((g_dmactrlflags & DMA_CTRL_PEN) == 0) 544799e125cSJiandong Zheng control |= D64_XC_PD; 545799e125cSJiandong Zheng 546799e125cSJiandong Zheng writel(control, GMAC0_DMA_TX_CTRL_ADDR); 547799e125cSJiandong Zheng 548799e125cSJiandong Zheng /* initailize the DMA channel */ 549799e125cSJiandong Zheng writel((uint32_t)(dma->tx_desc_aligned), 550799e125cSJiandong Zheng GMAC0_DMA_TX_ADDR_LOW_ADDR); 551799e125cSJiandong Zheng writel(0, GMAC0_DMA_TX_ADDR_HIGH_ADDR); 552799e125cSJiandong Zheng } else { 553799e125cSJiandong Zheng dma->cur_rx_index = 0; 554799e125cSJiandong Zheng 555799e125cSJiandong Zheng control = (readl(GMAC0_DMA_RX_CTRL_ADDR) & 556799e125cSJiandong Zheng D64_RC_AE) | D64_RC_RE; 557799e125cSJiandong Zheng 558799e125cSJiandong Zheng if ((g_dmactrlflags & DMA_CTRL_PEN) == 0) 559799e125cSJiandong Zheng control |= D64_RC_PD; 560799e125cSJiandong Zheng 561799e125cSJiandong Zheng if (g_dmactrlflags & DMA_CTRL_ROC) 562799e125cSJiandong Zheng control |= D64_RC_OC; 563799e125cSJiandong Zheng 564799e125cSJiandong Zheng /* 565799e125cSJiandong Zheng * These bits 20:18 (burstLen) of control register can be 566799e125cSJiandong Zheng * written but will take effect only if these bits are 567799e125cSJiandong Zheng * valid. So this will not affect previous versions 568799e125cSJiandong Zheng * of the DMA. They will continue to have those bits set to 0. 569799e125cSJiandong Zheng */ 570799e125cSJiandong Zheng control &= ~D64_RC_BL_MASK; 571799e125cSJiandong Zheng /* Keep default Rx burstlen */ 572799e125cSJiandong Zheng control |= readl(GMAC0_DMA_RX_CTRL_ADDR) & D64_RC_BL_MASK; 573799e125cSJiandong Zheng control |= HWRXOFF << D64_RC_RO_SHIFT; 574799e125cSJiandong Zheng 575799e125cSJiandong Zheng writel(control, GMAC0_DMA_RX_CTRL_ADDR); 576799e125cSJiandong Zheng 577799e125cSJiandong Zheng /* 578799e125cSJiandong Zheng * the rx descriptor ring should have 579799e125cSJiandong Zheng * the addresses set properly; 580799e125cSJiandong Zheng * set the lastdscr for the rx ring 581799e125cSJiandong Zheng */ 582799e125cSJiandong Zheng writel(((uint32_t)(dma->rx_desc_aligned) + 583*5c624b9eSSuji Velupillai (RX_BUF_NUM - 1) * RX_BUF_SIZE_ALIGNED) & 584799e125cSJiandong Zheng D64_XP_LD_MASK, GMAC0_DMA_RX_PTR_ADDR); 585799e125cSJiandong Zheng } 586799e125cSJiandong Zheng 587799e125cSJiandong Zheng return 0; 588799e125cSJiandong Zheng } 589799e125cSJiandong Zheng 590799e125cSJiandong Zheng bool gmac_mii_busywait(unsigned int timeout) 591799e125cSJiandong Zheng { 592799e125cSJiandong Zheng uint32_t tmp = 0; 593799e125cSJiandong Zheng 594799e125cSJiandong Zheng while (timeout > 10) { 595799e125cSJiandong Zheng tmp = readl(GMAC_MII_CTRL_ADDR); 596799e125cSJiandong Zheng if (tmp & (1 << GMAC_MII_BUSY_SHIFT)) { 597799e125cSJiandong Zheng udelay(10); 598799e125cSJiandong Zheng timeout -= 10; 599799e125cSJiandong Zheng } else { 600799e125cSJiandong Zheng break; 601799e125cSJiandong Zheng } 602799e125cSJiandong Zheng } 603799e125cSJiandong Zheng return tmp & (1 << GMAC_MII_BUSY_SHIFT); 604799e125cSJiandong Zheng } 605799e125cSJiandong Zheng 606dfcc496eSJoe Hershberger int gmac_miiphy_read(struct mii_dev *bus, int phyaddr, int devad, int reg) 607799e125cSJiandong Zheng { 608799e125cSJiandong Zheng uint32_t tmp = 0; 609dfcc496eSJoe Hershberger u16 value = 0; 610799e125cSJiandong Zheng 611799e125cSJiandong Zheng /* Busy wait timeout is 1ms */ 612799e125cSJiandong Zheng if (gmac_mii_busywait(1000)) { 613799e125cSJiandong Zheng error("%s: Prepare MII read: MII/MDIO busy\n", __func__); 614799e125cSJiandong Zheng return -1; 615799e125cSJiandong Zheng } 616799e125cSJiandong Zheng 617799e125cSJiandong Zheng /* Read operation */ 618799e125cSJiandong Zheng tmp = GMAC_MII_DATA_READ_CMD; 619799e125cSJiandong Zheng tmp |= (phyaddr << GMAC_MII_PHY_ADDR_SHIFT) | 620799e125cSJiandong Zheng (reg << GMAC_MII_PHY_REG_SHIFT); 621799e125cSJiandong Zheng debug("MII read cmd 0x%x, phy 0x%x, reg 0x%x\n", tmp, phyaddr, reg); 622799e125cSJiandong Zheng writel(tmp, GMAC_MII_DATA_ADDR); 623799e125cSJiandong Zheng 624799e125cSJiandong Zheng if (gmac_mii_busywait(1000)) { 625799e125cSJiandong Zheng error("%s: MII read failure: MII/MDIO busy\n", __func__); 626799e125cSJiandong Zheng return -1; 627799e125cSJiandong Zheng } 628799e125cSJiandong Zheng 629dfcc496eSJoe Hershberger value = readl(GMAC_MII_DATA_ADDR) & 0xffff; 630dfcc496eSJoe Hershberger debug("MII read data 0x%x\n", value); 631dfcc496eSJoe Hershberger return value; 632799e125cSJiandong Zheng } 633799e125cSJiandong Zheng 634dfcc496eSJoe Hershberger int gmac_miiphy_write(struct mii_dev *bus, int phyaddr, int devad, int reg, 635dfcc496eSJoe Hershberger u16 value) 636799e125cSJiandong Zheng { 637799e125cSJiandong Zheng uint32_t tmp = 0; 638799e125cSJiandong Zheng 639799e125cSJiandong Zheng /* Busy wait timeout is 1ms */ 640799e125cSJiandong Zheng if (gmac_mii_busywait(1000)) { 641799e125cSJiandong Zheng error("%s: Prepare MII write: MII/MDIO busy\n", __func__); 642799e125cSJiandong Zheng return -1; 643799e125cSJiandong Zheng } 644799e125cSJiandong Zheng 645799e125cSJiandong Zheng /* Write operation */ 646799e125cSJiandong Zheng tmp = GMAC_MII_DATA_WRITE_CMD | (value & 0xffff); 647799e125cSJiandong Zheng tmp |= ((phyaddr << GMAC_MII_PHY_ADDR_SHIFT) | 648799e125cSJiandong Zheng (reg << GMAC_MII_PHY_REG_SHIFT)); 649799e125cSJiandong Zheng debug("MII write cmd 0x%x, phy 0x%x, reg 0x%x, data 0x%x\n", 650799e125cSJiandong Zheng tmp, phyaddr, reg, value); 651799e125cSJiandong Zheng writel(tmp, GMAC_MII_DATA_ADDR); 652799e125cSJiandong Zheng 653799e125cSJiandong Zheng if (gmac_mii_busywait(1000)) { 654799e125cSJiandong Zheng error("%s: MII write failure: MII/MDIO busy\n", __func__); 655799e125cSJiandong Zheng return -1; 656799e125cSJiandong Zheng } 657799e125cSJiandong Zheng 658799e125cSJiandong Zheng return 0; 659799e125cSJiandong Zheng } 660799e125cSJiandong Zheng 661799e125cSJiandong Zheng void gmac_init_reset(void) 662799e125cSJiandong Zheng { 663799e125cSJiandong Zheng debug("%s enter\n", __func__); 664799e125cSJiandong Zheng 665799e125cSJiandong Zheng /* set command config reg CC_SR */ 666799e125cSJiandong Zheng reg32_set_bits(UNIMAC0_CMD_CFG_ADDR, CC_SR); 667799e125cSJiandong Zheng udelay(GMAC_RESET_DELAY); 668799e125cSJiandong Zheng } 669799e125cSJiandong Zheng 670799e125cSJiandong Zheng void gmac_clear_reset(void) 671799e125cSJiandong Zheng { 672799e125cSJiandong Zheng debug("%s enter\n", __func__); 673799e125cSJiandong Zheng 674799e125cSJiandong Zheng /* clear command config reg CC_SR */ 675799e125cSJiandong Zheng reg32_clear_bits(UNIMAC0_CMD_CFG_ADDR, CC_SR); 676799e125cSJiandong Zheng udelay(GMAC_RESET_DELAY); 677799e125cSJiandong Zheng } 678799e125cSJiandong Zheng 679799e125cSJiandong Zheng static void gmac_enable_local(bool en) 680799e125cSJiandong Zheng { 681799e125cSJiandong Zheng uint32_t cmdcfg; 682799e125cSJiandong Zheng 683799e125cSJiandong Zheng debug("%s enter\n", __func__); 684799e125cSJiandong Zheng 685799e125cSJiandong Zheng /* read command config reg */ 686799e125cSJiandong Zheng cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR); 687799e125cSJiandong Zheng 688799e125cSJiandong Zheng /* put mac in reset */ 689799e125cSJiandong Zheng gmac_init_reset(); 690799e125cSJiandong Zheng 691799e125cSJiandong Zheng cmdcfg |= CC_SR; 692799e125cSJiandong Zheng 693799e125cSJiandong Zheng /* first deassert rx_ena and tx_ena while in reset */ 694799e125cSJiandong Zheng cmdcfg &= ~(CC_RE | CC_TE); 695799e125cSJiandong Zheng /* write command config reg */ 696799e125cSJiandong Zheng writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR); 697799e125cSJiandong Zheng 698799e125cSJiandong Zheng /* bring mac out of reset */ 699799e125cSJiandong Zheng gmac_clear_reset(); 700799e125cSJiandong Zheng 701799e125cSJiandong Zheng /* if not enable exit now */ 702799e125cSJiandong Zheng if (!en) 703799e125cSJiandong Zheng return; 704799e125cSJiandong Zheng 705799e125cSJiandong Zheng /* enable the mac transmit and receive paths now */ 706799e125cSJiandong Zheng udelay(2); 707799e125cSJiandong Zheng cmdcfg &= ~CC_SR; 708799e125cSJiandong Zheng cmdcfg |= (CC_RE | CC_TE); 709799e125cSJiandong Zheng 710799e125cSJiandong Zheng /* assert rx_ena and tx_ena when out of reset to enable the mac */ 711799e125cSJiandong Zheng writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR); 712799e125cSJiandong Zheng 713799e125cSJiandong Zheng return; 714799e125cSJiandong Zheng } 715799e125cSJiandong Zheng 716799e125cSJiandong Zheng int gmac_enable(void) 717799e125cSJiandong Zheng { 718799e125cSJiandong Zheng gmac_enable_local(1); 719799e125cSJiandong Zheng 720799e125cSJiandong Zheng /* clear interrupts */ 721799e125cSJiandong Zheng writel(I_INTMASK, GMAC0_INT_STATUS_ADDR); 722799e125cSJiandong Zheng return 0; 723799e125cSJiandong Zheng } 724799e125cSJiandong Zheng 725799e125cSJiandong Zheng int gmac_disable(void) 726799e125cSJiandong Zheng { 727799e125cSJiandong Zheng gmac_enable_local(0); 728799e125cSJiandong Zheng return 0; 729799e125cSJiandong Zheng } 730799e125cSJiandong Zheng 731799e125cSJiandong Zheng int gmac_set_speed(int speed, int duplex) 732799e125cSJiandong Zheng { 733799e125cSJiandong Zheng uint32_t cmdcfg; 734799e125cSJiandong Zheng uint32_t hd_ena; 735799e125cSJiandong Zheng uint32_t speed_cfg; 736799e125cSJiandong Zheng 737799e125cSJiandong Zheng hd_ena = duplex ? 0 : CC_HD; 738799e125cSJiandong Zheng if (speed == 1000) { 739799e125cSJiandong Zheng speed_cfg = 2; 740799e125cSJiandong Zheng } else if (speed == 100) { 741799e125cSJiandong Zheng speed_cfg = 1; 742799e125cSJiandong Zheng } else if (speed == 10) { 743799e125cSJiandong Zheng speed_cfg = 0; 744799e125cSJiandong Zheng } else { 745799e125cSJiandong Zheng error("%s: Invalid GMAC speed(%d)!\n", __func__, speed); 746799e125cSJiandong Zheng return -1; 747799e125cSJiandong Zheng } 748799e125cSJiandong Zheng 749799e125cSJiandong Zheng cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR); 750799e125cSJiandong Zheng cmdcfg &= ~(CC_ES_MASK | CC_HD); 751799e125cSJiandong Zheng cmdcfg |= ((speed_cfg << CC_ES_SHIFT) | hd_ena); 752799e125cSJiandong Zheng 753799e125cSJiandong Zheng printf("Change GMAC speed to %dMB\n", speed); 754799e125cSJiandong Zheng debug("GMAC speed cfg 0x%x\n", cmdcfg); 755799e125cSJiandong Zheng writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR); 756799e125cSJiandong Zheng 757799e125cSJiandong Zheng return 0; 758799e125cSJiandong Zheng } 759799e125cSJiandong Zheng 760799e125cSJiandong Zheng int gmac_set_mac_addr(unsigned char *mac) 761799e125cSJiandong Zheng { 762799e125cSJiandong Zheng /* set our local address */ 763799e125cSJiandong Zheng debug("GMAC: %02x:%02x:%02x:%02x:%02x:%02x\n", 764799e125cSJiandong Zheng mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 765799e125cSJiandong Zheng writel(htonl(*(uint32_t *)mac), UNIMAC0_MAC_MSB_ADDR); 766799e125cSJiandong Zheng writew(htons(*(uint32_t *)&mac[4]), UNIMAC0_MAC_LSB_ADDR); 767799e125cSJiandong Zheng 768799e125cSJiandong Zheng return 0; 769799e125cSJiandong Zheng } 770799e125cSJiandong Zheng 771799e125cSJiandong Zheng int gmac_mac_init(struct eth_device *dev) 772799e125cSJiandong Zheng { 773799e125cSJiandong Zheng struct eth_info *eth = (struct eth_info *)(dev->priv); 774799e125cSJiandong Zheng struct eth_dma *dma = &(eth->dma); 775799e125cSJiandong Zheng 776799e125cSJiandong Zheng uint32_t tmp; 777799e125cSJiandong Zheng uint32_t cmdcfg; 778799e125cSJiandong Zheng int chipid; 779799e125cSJiandong Zheng 780799e125cSJiandong Zheng debug("%s enter\n", __func__); 781799e125cSJiandong Zheng 782799e125cSJiandong Zheng /* Always use GMAC0 */ 783799e125cSJiandong Zheng printf("Using GMAC%d\n", 0); 784799e125cSJiandong Zheng 785799e125cSJiandong Zheng /* Reset AMAC0 core */ 786799e125cSJiandong Zheng writel(0, AMAC0_IDM_RESET_ADDR); 787799e125cSJiandong Zheng tmp = readl(AMAC0_IO_CTRL_DIRECT_ADDR); 788799e125cSJiandong Zheng /* Set clock */ 789799e125cSJiandong Zheng tmp &= ~(1 << AMAC0_IO_CTRL_CLK_250_SEL_SHIFT); 790799e125cSJiandong Zheng tmp |= (1 << AMAC0_IO_CTRL_GMII_MODE_SHIFT); 791799e125cSJiandong Zheng /* Set Tx clock */ 792799e125cSJiandong Zheng tmp &= ~(1 << AMAC0_IO_CTRL_DEST_SYNC_MODE_EN_SHIFT); 793799e125cSJiandong Zheng writel(tmp, AMAC0_IO_CTRL_DIRECT_ADDR); 794799e125cSJiandong Zheng 795799e125cSJiandong Zheng /* reset gmac */ 796799e125cSJiandong Zheng /* 797799e125cSJiandong Zheng * As AMAC is just reset, NO need? 798799e125cSJiandong Zheng * set eth_data into loopback mode to ensure no rx traffic 799799e125cSJiandong Zheng * gmac_loopback(eth_data, TRUE); 800799e125cSJiandong Zheng * ET_TRACE(("%s gmac loopback\n", __func__)); 801799e125cSJiandong Zheng * udelay(1); 802799e125cSJiandong Zheng */ 803799e125cSJiandong Zheng 804799e125cSJiandong Zheng cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR); 805799e125cSJiandong Zheng cmdcfg &= ~(CC_TE | CC_RE | CC_RPI | CC_TAI | CC_HD | CC_ML | 806799e125cSJiandong Zheng CC_CFE | CC_RL | CC_RED | CC_PE | CC_TPI | 807799e125cSJiandong Zheng CC_PAD_EN | CC_PF); 808799e125cSJiandong Zheng cmdcfg |= (CC_PROM | CC_NLC | CC_CFE); 809799e125cSJiandong Zheng /* put mac in reset */ 810799e125cSJiandong Zheng gmac_init_reset(); 811799e125cSJiandong Zheng writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR); 812799e125cSJiandong Zheng gmac_clear_reset(); 813799e125cSJiandong Zheng 814799e125cSJiandong Zheng /* enable clear MIB on read */ 815799e125cSJiandong Zheng reg32_set_bits(GMAC0_DEV_CTRL_ADDR, DC_MROR); 816799e125cSJiandong Zheng /* PHY: set smi_master to drive mdc_clk */ 817799e125cSJiandong Zheng reg32_set_bits(GMAC0_PHY_CTRL_ADDR, PC_MTE); 818799e125cSJiandong Zheng 819799e125cSJiandong Zheng /* clear persistent sw intstatus */ 820799e125cSJiandong Zheng writel(0, GMAC0_INT_STATUS_ADDR); 821799e125cSJiandong Zheng 822799e125cSJiandong Zheng if (dma_init(dma) < 0) { 823799e125cSJiandong Zheng error("%s: GMAC dma_init failed\n", __func__); 824799e125cSJiandong Zheng goto err_exit; 825799e125cSJiandong Zheng } 826799e125cSJiandong Zheng 827799e125cSJiandong Zheng chipid = CHIPID; 828799e125cSJiandong Zheng printf("%s: Chip ID: 0x%x\n", __func__, chipid); 829799e125cSJiandong Zheng 830799e125cSJiandong Zheng /* set switch bypass mode */ 831799e125cSJiandong Zheng tmp = readl(SWITCH_GLOBAL_CONFIG_ADDR); 832799e125cSJiandong Zheng tmp |= (1 << CDRU_SWITCH_BYPASS_SWITCH_SHIFT); 833799e125cSJiandong Zheng 834799e125cSJiandong Zheng /* Switch mode */ 835799e125cSJiandong Zheng /* tmp &= ~(1 << CDRU_SWITCH_BYPASS_SWITCH_SHIFT); */ 836799e125cSJiandong Zheng 837799e125cSJiandong Zheng writel(tmp, SWITCH_GLOBAL_CONFIG_ADDR); 838799e125cSJiandong Zheng 839799e125cSJiandong Zheng tmp = readl(CRMU_CHIP_IO_PAD_CONTROL_ADDR); 840799e125cSJiandong Zheng tmp &= ~(1 << CDRU_IOMUX_FORCE_PAD_IN_SHIFT); 841799e125cSJiandong Zheng writel(tmp, CRMU_CHIP_IO_PAD_CONTROL_ADDR); 842799e125cSJiandong Zheng 843799e125cSJiandong Zheng /* Set MDIO to internal GPHY */ 844799e125cSJiandong Zheng tmp = readl(GMAC_MII_CTRL_ADDR); 845799e125cSJiandong Zheng /* Select internal MDC/MDIO bus*/ 846799e125cSJiandong Zheng tmp &= ~(1 << GMAC_MII_CTRL_BYP_SHIFT); 847799e125cSJiandong Zheng /* select MDC/MDIO connecting to on-chip internal PHYs */ 848799e125cSJiandong Zheng tmp &= ~(1 << GMAC_MII_CTRL_EXT_SHIFT); 849799e125cSJiandong Zheng /* 850799e125cSJiandong Zheng * give bit[6:0](MDCDIV) with required divisor to set 851799e125cSJiandong Zheng * the MDC clock frequency, 66MHZ/0x1A=2.5MHZ 852799e125cSJiandong Zheng */ 853799e125cSJiandong Zheng tmp |= 0x1A; 854799e125cSJiandong Zheng 855799e125cSJiandong Zheng writel(tmp, GMAC_MII_CTRL_ADDR); 856799e125cSJiandong Zheng 857799e125cSJiandong Zheng if (gmac_mii_busywait(1000)) { 858799e125cSJiandong Zheng error("%s: Configure MDIO: MII/MDIO busy\n", __func__); 859799e125cSJiandong Zheng goto err_exit; 860799e125cSJiandong Zheng } 861799e125cSJiandong Zheng 862799e125cSJiandong Zheng /* Configure GMAC0 */ 863799e125cSJiandong Zheng /* enable one rx interrupt per received frame */ 864799e125cSJiandong Zheng writel(1 << GMAC0_IRL_FRAMECOUNT_SHIFT, GMAC0_INTR_RECV_LAZY_ADDR); 865799e125cSJiandong Zheng 866799e125cSJiandong Zheng /* read command config reg */ 867799e125cSJiandong Zheng cmdcfg = readl(UNIMAC0_CMD_CFG_ADDR); 868799e125cSJiandong Zheng /* enable 802.3x tx flow control (honor received PAUSE frames) */ 869799e125cSJiandong Zheng cmdcfg &= ~CC_RPI; 870799e125cSJiandong Zheng /* enable promiscuous mode */ 871799e125cSJiandong Zheng cmdcfg |= CC_PROM; 872799e125cSJiandong Zheng /* Disable loopback mode */ 873799e125cSJiandong Zheng cmdcfg &= ~CC_ML; 874799e125cSJiandong Zheng /* set the speed */ 875799e125cSJiandong Zheng cmdcfg &= ~(CC_ES_MASK | CC_HD); 876799e125cSJiandong Zheng /* Set to 1Gbps and full duplex by default */ 877799e125cSJiandong Zheng cmdcfg |= (2 << CC_ES_SHIFT); 878799e125cSJiandong Zheng 879799e125cSJiandong Zheng /* put mac in reset */ 880799e125cSJiandong Zheng gmac_init_reset(); 881799e125cSJiandong Zheng /* write register */ 882799e125cSJiandong Zheng writel(cmdcfg, UNIMAC0_CMD_CFG_ADDR); 883799e125cSJiandong Zheng /* bring mac out of reset */ 884799e125cSJiandong Zheng gmac_clear_reset(); 885799e125cSJiandong Zheng 886799e125cSJiandong Zheng /* set max frame lengths; account for possible vlan tag */ 887799e125cSJiandong Zheng writel(PKTSIZE + 32, UNIMAC0_FRM_LENGTH_ADDR); 888799e125cSJiandong Zheng 889799e125cSJiandong Zheng return 0; 890799e125cSJiandong Zheng 891799e125cSJiandong Zheng err_exit: 892799e125cSJiandong Zheng dma_deinit(dma); 893799e125cSJiandong Zheng return -1; 894799e125cSJiandong Zheng } 895799e125cSJiandong Zheng 896799e125cSJiandong Zheng int gmac_add(struct eth_device *dev) 897799e125cSJiandong Zheng { 898799e125cSJiandong Zheng struct eth_info *eth = (struct eth_info *)(dev->priv); 899799e125cSJiandong Zheng struct eth_dma *dma = &(eth->dma); 900799e125cSJiandong Zheng void *tmp; 901799e125cSJiandong Zheng 902799e125cSJiandong Zheng /* 903*5c624b9eSSuji Velupillai * Desc has to be 16-byte aligned. But for dcache flush it must be 904*5c624b9eSSuji Velupillai * aligned to ARCH_DMA_MINALIGN. 905799e125cSJiandong Zheng */ 906*5c624b9eSSuji Velupillai tmp = memalign(ARCH_DMA_MINALIGN, DESCP_SIZE_ALIGNED * TX_BUF_NUM); 907799e125cSJiandong Zheng if (tmp == NULL) { 908799e125cSJiandong Zheng printf("%s: Failed to allocate TX desc Buffer\n", __func__); 909799e125cSJiandong Zheng return -1; 910799e125cSJiandong Zheng } 911799e125cSJiandong Zheng 912*5c624b9eSSuji Velupillai dma->tx_desc_aligned = (void *)tmp; 913799e125cSJiandong Zheng debug("TX Descriptor Buffer: %p; length: 0x%x\n", 914*5c624b9eSSuji Velupillai dma->tx_desc_aligned, DESCP_SIZE_ALIGNED * TX_BUF_NUM); 915799e125cSJiandong Zheng 916*5c624b9eSSuji Velupillai tmp = memalign(ARCH_DMA_MINALIGN, TX_BUF_SIZE_ALIGNED * TX_BUF_NUM); 917799e125cSJiandong Zheng if (tmp == NULL) { 918799e125cSJiandong Zheng printf("%s: Failed to allocate TX Data Buffer\n", __func__); 919*5c624b9eSSuji Velupillai free(dma->tx_desc_aligned); 920799e125cSJiandong Zheng return -1; 921799e125cSJiandong Zheng } 922799e125cSJiandong Zheng dma->tx_buf = (uint8_t *)tmp; 923799e125cSJiandong Zheng debug("TX Data Buffer: %p; length: 0x%x\n", 924*5c624b9eSSuji Velupillai dma->tx_buf, TX_BUF_SIZE_ALIGNED * TX_BUF_NUM); 925799e125cSJiandong Zheng 926*5c624b9eSSuji Velupillai /* Desc has to be 16-byte aligned */ 927*5c624b9eSSuji Velupillai tmp = memalign(ARCH_DMA_MINALIGN, DESCP_SIZE_ALIGNED * RX_BUF_NUM); 928799e125cSJiandong Zheng if (tmp == NULL) { 929799e125cSJiandong Zheng printf("%s: Failed to allocate RX Descriptor\n", __func__); 930*5c624b9eSSuji Velupillai free(dma->tx_desc_aligned); 931799e125cSJiandong Zheng free(dma->tx_buf); 932799e125cSJiandong Zheng return -1; 933799e125cSJiandong Zheng } 934*5c624b9eSSuji Velupillai dma->rx_desc_aligned = (void *)tmp; 935799e125cSJiandong Zheng debug("RX Descriptor Buffer: %p, length: 0x%x\n", 936*5c624b9eSSuji Velupillai dma->rx_desc_aligned, DESCP_SIZE_ALIGNED * RX_BUF_NUM); 937799e125cSJiandong Zheng 938*5c624b9eSSuji Velupillai tmp = memalign(ARCH_DMA_MINALIGN, RX_BUF_SIZE_ALIGNED * RX_BUF_NUM); 939799e125cSJiandong Zheng if (tmp == NULL) { 940799e125cSJiandong Zheng printf("%s: Failed to allocate RX Data Buffer\n", __func__); 941*5c624b9eSSuji Velupillai free(dma->tx_desc_aligned); 942799e125cSJiandong Zheng free(dma->tx_buf); 943*5c624b9eSSuji Velupillai free(dma->rx_desc_aligned); 944799e125cSJiandong Zheng return -1; 945799e125cSJiandong Zheng } 946*5c624b9eSSuji Velupillai dma->rx_buf = (uint8_t *)tmp; 947799e125cSJiandong Zheng debug("RX Data Buffer: %p; length: 0x%x\n", 948*5c624b9eSSuji Velupillai dma->rx_buf, RX_BUF_SIZE_ALIGNED * RX_BUF_NUM); 949799e125cSJiandong Zheng 950799e125cSJiandong Zheng g_dmactrlflags = 0; 951799e125cSJiandong Zheng 952799e125cSJiandong Zheng eth->phy_interface = PHY_INTERFACE_MODE_GMII; 953799e125cSJiandong Zheng 954799e125cSJiandong Zheng dma->tx_packet = gmac_tx_packet; 955799e125cSJiandong Zheng dma->check_tx_done = gmac_check_tx_done; 956799e125cSJiandong Zheng 957799e125cSJiandong Zheng dma->check_rx_done = gmac_check_rx_done; 958799e125cSJiandong Zheng 959799e125cSJiandong Zheng dma->enable_dma = gmac_enable_dma; 960799e125cSJiandong Zheng dma->disable_dma = gmac_disable_dma; 961799e125cSJiandong Zheng 962799e125cSJiandong Zheng eth->miiphy_read = gmac_miiphy_read; 963799e125cSJiandong Zheng eth->miiphy_write = gmac_miiphy_write; 964799e125cSJiandong Zheng 965799e125cSJiandong Zheng eth->mac_init = gmac_mac_init; 966799e125cSJiandong Zheng eth->disable_mac = gmac_disable; 967799e125cSJiandong Zheng eth->enable_mac = gmac_enable; 968799e125cSJiandong Zheng eth->set_mac_addr = gmac_set_mac_addr; 969799e125cSJiandong Zheng eth->set_mac_speed = gmac_set_speed; 970799e125cSJiandong Zheng 971799e125cSJiandong Zheng return 0; 972799e125cSJiandong Zheng } 973