17ac6653aSJeff Kirsher /******************************************************************************* 27ac6653aSJeff Kirsher This is the driver for the MAC 10/100 on-chip Ethernet controller 37ac6653aSJeff Kirsher currently tested on all the ST boards based on STb7109 and stx7200 SoCs. 47ac6653aSJeff Kirsher 57ac6653aSJeff Kirsher DWC Ether MAC 10/100 Universal version 4.0 has been used for developing 67ac6653aSJeff Kirsher this code. 77ac6653aSJeff Kirsher 87ac6653aSJeff Kirsher This contains the functions to handle the dma. 97ac6653aSJeff Kirsher 107ac6653aSJeff Kirsher Copyright (C) 2007-2009 STMicroelectronics Ltd 117ac6653aSJeff Kirsher 127ac6653aSJeff Kirsher This program is free software; you can redistribute it and/or modify it 137ac6653aSJeff Kirsher under the terms and conditions of the GNU General Public License, 147ac6653aSJeff Kirsher version 2, as published by the Free Software Foundation. 157ac6653aSJeff Kirsher 167ac6653aSJeff Kirsher This program is distributed in the hope it will be useful, but WITHOUT 177ac6653aSJeff Kirsher ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 187ac6653aSJeff Kirsher FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 197ac6653aSJeff Kirsher more details. 207ac6653aSJeff Kirsher 217ac6653aSJeff Kirsher You should have received a copy of the GNU General Public License along with 227ac6653aSJeff Kirsher this program; if not, write to the Free Software Foundation, Inc., 237ac6653aSJeff Kirsher 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 247ac6653aSJeff Kirsher 257ac6653aSJeff Kirsher The full GNU General Public License is included in this distribution in 267ac6653aSJeff Kirsher the file called "COPYING". 277ac6653aSJeff Kirsher 287ac6653aSJeff Kirsher Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> 297ac6653aSJeff Kirsher *******************************************************************************/ 307ac6653aSJeff Kirsher 317ac6653aSJeff Kirsher #include <asm/io.h> 327ac6653aSJeff Kirsher #include "dwmac100.h" 337ac6653aSJeff Kirsher #include "dwmac_dma.h" 347ac6653aSJeff Kirsher 35c24602efSGiuseppe CAVALLARO static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb, 36c24602efSGiuseppe CAVALLARO int burst_len, u32 dma_tx, u32 dma_rx, int atds) 377ac6653aSJeff Kirsher { 387ac6653aSJeff Kirsher u32 value = readl(ioaddr + DMA_BUS_MODE); 397ac6653aSJeff Kirsher int limit; 407ac6653aSJeff Kirsher 417ac6653aSJeff Kirsher /* DMA SW reset */ 427ac6653aSJeff Kirsher value |= DMA_BUS_MODE_SFT_RESET; 437ac6653aSJeff Kirsher writel(value, ioaddr + DMA_BUS_MODE); 44bbc17546SFrancesco Virlinzi limit = 10; 457ac6653aSJeff Kirsher while (limit--) { 467ac6653aSJeff Kirsher if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) 477ac6653aSJeff Kirsher break; 48bbc17546SFrancesco Virlinzi mdelay(10); 497ac6653aSJeff Kirsher } 507ac6653aSJeff Kirsher if (limit < 0) 517ac6653aSJeff Kirsher return -EBUSY; 527ac6653aSJeff Kirsher 537ac6653aSJeff Kirsher /* Enable Application Access by writing to DMA CSR0 */ 547ac6653aSJeff Kirsher writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT), 557ac6653aSJeff Kirsher ioaddr + DMA_BUS_MODE); 567ac6653aSJeff Kirsher 577ac6653aSJeff Kirsher /* Mask interrupts by writing to CSR7 */ 587ac6653aSJeff Kirsher writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); 597ac6653aSJeff Kirsher 607ac6653aSJeff Kirsher /* The base address of the RX/TX descriptor lists must be written into 617ac6653aSJeff Kirsher * DMA CSR3 and CSR4, respectively. */ 627ac6653aSJeff Kirsher writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR); 637ac6653aSJeff Kirsher writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR); 647ac6653aSJeff Kirsher 657ac6653aSJeff Kirsher return 0; 667ac6653aSJeff Kirsher } 677ac6653aSJeff Kirsher 687ac6653aSJeff Kirsher /* Store and Forward capability is not used at all.. 697ac6653aSJeff Kirsher * The transmit threshold can be programmed by 707ac6653aSJeff Kirsher * setting the TTC bits in the DMA control register.*/ 717ac6653aSJeff Kirsher static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode, 727ac6653aSJeff Kirsher int rxmode) 737ac6653aSJeff Kirsher { 747ac6653aSJeff Kirsher u32 csr6 = readl(ioaddr + DMA_CONTROL); 757ac6653aSJeff Kirsher 767ac6653aSJeff Kirsher if (txmode <= 32) 777ac6653aSJeff Kirsher csr6 |= DMA_CONTROL_TTC_32; 787ac6653aSJeff Kirsher else if (txmode <= 64) 797ac6653aSJeff Kirsher csr6 |= DMA_CONTROL_TTC_64; 807ac6653aSJeff Kirsher else 817ac6653aSJeff Kirsher csr6 |= DMA_CONTROL_TTC_128; 827ac6653aSJeff Kirsher 837ac6653aSJeff Kirsher writel(csr6, ioaddr + DMA_CONTROL); 847ac6653aSJeff Kirsher } 857ac6653aSJeff Kirsher 867ac6653aSJeff Kirsher static void dwmac100_dump_dma_regs(void __iomem *ioaddr) 877ac6653aSJeff Kirsher { 887ac6653aSJeff Kirsher int i; 897ac6653aSJeff Kirsher 907ac6653aSJeff Kirsher CHIP_DBG(KERN_DEBUG "DWMAC 100 DMA CSR\n"); 917ac6653aSJeff Kirsher for (i = 0; i < 9; i++) 927ac6653aSJeff Kirsher pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i, 937ac6653aSJeff Kirsher (DMA_BUS_MODE + i * 4), 947ac6653aSJeff Kirsher readl(ioaddr + DMA_BUS_MODE + i * 4)); 957ac6653aSJeff Kirsher CHIP_DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n", 967ac6653aSJeff Kirsher DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR)); 977ac6653aSJeff Kirsher CHIP_DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n", 987ac6653aSJeff Kirsher DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR)); 997ac6653aSJeff Kirsher } 1007ac6653aSJeff Kirsher 1017ac6653aSJeff Kirsher /* DMA controller has two counters to track the number of 1027ac6653aSJeff Kirsher * the receive missed frames. */ 1037ac6653aSJeff Kirsher static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x, 1047ac6653aSJeff Kirsher void __iomem *ioaddr) 1057ac6653aSJeff Kirsher { 1067ac6653aSJeff Kirsher struct net_device_stats *stats = (struct net_device_stats *)data; 1077ac6653aSJeff Kirsher u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR); 1087ac6653aSJeff Kirsher 1097ac6653aSJeff Kirsher if (unlikely(csr8)) { 1107ac6653aSJeff Kirsher if (csr8 & DMA_MISSED_FRAME_OVE) { 1117ac6653aSJeff Kirsher stats->rx_over_errors += 0x800; 1127ac6653aSJeff Kirsher x->rx_overflow_cntr += 0x800; 1137ac6653aSJeff Kirsher } else { 1147ac6653aSJeff Kirsher unsigned int ove_cntr; 1157ac6653aSJeff Kirsher ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17); 1167ac6653aSJeff Kirsher stats->rx_over_errors += ove_cntr; 1177ac6653aSJeff Kirsher x->rx_overflow_cntr += ove_cntr; 1187ac6653aSJeff Kirsher } 1197ac6653aSJeff Kirsher 1207ac6653aSJeff Kirsher if (csr8 & DMA_MISSED_FRAME_OVE_M) { 1217ac6653aSJeff Kirsher stats->rx_missed_errors += 0xffff; 1227ac6653aSJeff Kirsher x->rx_missed_cntr += 0xffff; 1237ac6653aSJeff Kirsher } else { 1247ac6653aSJeff Kirsher unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR); 1257ac6653aSJeff Kirsher stats->rx_missed_errors += miss_f; 1267ac6653aSJeff Kirsher x->rx_missed_cntr += miss_f; 1277ac6653aSJeff Kirsher } 1287ac6653aSJeff Kirsher } 1297ac6653aSJeff Kirsher } 1307ac6653aSJeff Kirsher 1317ac6653aSJeff Kirsher const struct stmmac_dma_ops dwmac100_dma_ops = { 1327ac6653aSJeff Kirsher .init = dwmac100_dma_init, 1337ac6653aSJeff Kirsher .dump_regs = dwmac100_dump_dma_regs, 1347ac6653aSJeff Kirsher .dma_mode = dwmac100_dma_operation_mode, 1357ac6653aSJeff Kirsher .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr, 1367ac6653aSJeff Kirsher .enable_dma_transmission = dwmac_enable_dma_transmission, 1377ac6653aSJeff Kirsher .enable_dma_irq = dwmac_enable_dma_irq, 1387ac6653aSJeff Kirsher .disable_dma_irq = dwmac_disable_dma_irq, 1397ac6653aSJeff Kirsher .start_tx = dwmac_dma_start_tx, 1407ac6653aSJeff Kirsher .stop_tx = dwmac_dma_stop_tx, 1417ac6653aSJeff Kirsher .start_rx = dwmac_dma_start_rx, 1427ac6653aSJeff Kirsher .stop_rx = dwmac_dma_stop_rx, 1437ac6653aSJeff Kirsher .dma_interrupt = dwmac_dma_interrupt, 1447ac6653aSJeff Kirsher }; 145