1 /******************************************************************************* 2 Copyright (C) 2007-2009 STMicroelectronics Ltd 3 4 This program is free software; you can redistribute it and/or modify it 5 under the terms and conditions of the GNU General Public License, 6 version 2, as published by the Free Software Foundation. 7 8 This program is distributed in the hope it will be useful, but WITHOUT 9 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 more details. 12 13 The full GNU General Public License is included in this distribution in 14 the file called "COPYING". 15 16 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> 17 *******************************************************************************/ 18 19 #include <linux/io.h> 20 #include <linux/iopoll.h> 21 #include "common.h" 22 #include "dwmac_dma.h" 23 24 #define GMAC_HI_REG_AE 0x80000000 25 26 int dwmac_dma_reset(void __iomem *ioaddr) 27 { 28 u32 value = readl(ioaddr + DMA_BUS_MODE); 29 int err; 30 31 /* DMA SW reset */ 32 value |= DMA_BUS_MODE_SFT_RESET; 33 writel(value, ioaddr + DMA_BUS_MODE); 34 35 err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value, 36 !(value & DMA_BUS_MODE_SFT_RESET), 37 10000, 100000); 38 if (err) 39 return -EBUSY; 40 41 return 0; 42 } 43 44 /* CSR1 enables the transmit DMA to check for new descriptor */ 45 void dwmac_enable_dma_transmission(void __iomem *ioaddr) 46 { 47 writel(1, ioaddr + DMA_XMT_POLL_DEMAND); 48 } 49 50 void dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan) 51 { 52 writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); 53 } 54 55 void dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan) 56 { 57 writel(0, ioaddr + DMA_INTR_ENA); 58 } 59 60 void dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan) 61 { 62 u32 value = readl(ioaddr + DMA_CONTROL); 63 value |= DMA_CONTROL_ST; 64 writel(value, ioaddr + DMA_CONTROL); 65 } 66 67 void dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan) 68 { 69 u32 value = readl(ioaddr + DMA_CONTROL); 70 value &= ~DMA_CONTROL_ST; 71 writel(value, ioaddr + DMA_CONTROL); 72 } 73 74 void dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan) 75 { 76 u32 value = readl(ioaddr + DMA_CONTROL); 77 value |= DMA_CONTROL_SR; 78 writel(value, ioaddr + DMA_CONTROL); 79 } 80 81 void dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan) 82 { 83 u32 value = readl(ioaddr + DMA_CONTROL); 84 value &= ~DMA_CONTROL_SR; 85 writel(value, ioaddr + DMA_CONTROL); 86 } 87 88 #ifdef DWMAC_DMA_DEBUG 89 static void show_tx_process_state(unsigned int status) 90 { 91 unsigned int state; 92 state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT; 93 94 switch (state) { 95 case 0: 96 pr_debug("- TX (Stopped): Reset or Stop command\n"); 97 break; 98 case 1: 99 pr_debug("- TX (Running): Fetching the Tx desc\n"); 100 break; 101 case 2: 102 pr_debug("- TX (Running): Waiting for end of tx\n"); 103 break; 104 case 3: 105 pr_debug("- TX (Running): Reading the data " 106 "and queuing the data into the Tx buf\n"); 107 break; 108 case 6: 109 pr_debug("- TX (Suspended): Tx Buff Underflow " 110 "or an unavailable Transmit descriptor\n"); 111 break; 112 case 7: 113 pr_debug("- TX (Running): Closing Tx descriptor\n"); 114 break; 115 default: 116 break; 117 } 118 } 119 120 static void show_rx_process_state(unsigned int status) 121 { 122 unsigned int state; 123 state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT; 124 125 switch (state) { 126 case 0: 127 pr_debug("- RX (Stopped): Reset or Stop command\n"); 128 break; 129 case 1: 130 pr_debug("- RX (Running): Fetching the Rx desc\n"); 131 break; 132 case 2: 133 pr_debug("- RX (Running): Checking for end of pkt\n"); 134 break; 135 case 3: 136 pr_debug("- RX (Running): Waiting for Rx pkt\n"); 137 break; 138 case 4: 139 pr_debug("- RX (Suspended): Unavailable Rx buf\n"); 140 break; 141 case 5: 142 pr_debug("- RX (Running): Closing Rx descriptor\n"); 143 break; 144 case 6: 145 pr_debug("- RX(Running): Flushing the current frame" 146 " from the Rx buf\n"); 147 break; 148 case 7: 149 pr_debug("- RX (Running): Queuing the Rx frame" 150 " from the Rx buf into memory\n"); 151 break; 152 default: 153 break; 154 } 155 } 156 #endif 157 158 int dwmac_dma_interrupt(void __iomem *ioaddr, 159 struct stmmac_extra_stats *x, u32 chan) 160 { 161 int ret = 0; 162 /* read the status register (CSR5) */ 163 u32 intr_status = readl(ioaddr + DMA_STATUS); 164 165 #ifdef DWMAC_DMA_DEBUG 166 /* Enable it to monitor DMA rx/tx status in case of critical problems */ 167 pr_debug("%s: [CSR5: 0x%08x]\n", __func__, intr_status); 168 show_tx_process_state(intr_status); 169 show_rx_process_state(intr_status); 170 #endif 171 /* ABNORMAL interrupts */ 172 if (unlikely(intr_status & DMA_STATUS_AIS)) { 173 if (unlikely(intr_status & DMA_STATUS_UNF)) { 174 ret = tx_hard_error_bump_tc; 175 x->tx_undeflow_irq++; 176 } 177 if (unlikely(intr_status & DMA_STATUS_TJT)) 178 x->tx_jabber_irq++; 179 180 if (unlikely(intr_status & DMA_STATUS_OVF)) 181 x->rx_overflow_irq++; 182 183 if (unlikely(intr_status & DMA_STATUS_RU)) 184 x->rx_buf_unav_irq++; 185 if (unlikely(intr_status & DMA_STATUS_RPS)) 186 x->rx_process_stopped_irq++; 187 if (unlikely(intr_status & DMA_STATUS_RWT)) 188 x->rx_watchdog_irq++; 189 if (unlikely(intr_status & DMA_STATUS_ETI)) 190 x->tx_early_irq++; 191 if (unlikely(intr_status & DMA_STATUS_TPS)) { 192 x->tx_process_stopped_irq++; 193 ret = tx_hard_error; 194 } 195 if (unlikely(intr_status & DMA_STATUS_FBI)) { 196 x->fatal_bus_error_irq++; 197 ret = tx_hard_error; 198 } 199 } 200 /* TX/RX NORMAL interrupts */ 201 if (likely(intr_status & DMA_STATUS_NIS)) { 202 x->normal_irq_n++; 203 if (likely(intr_status & DMA_STATUS_RI)) { 204 u32 value = readl(ioaddr + DMA_INTR_ENA); 205 /* to schedule NAPI on real RIE event. */ 206 if (likely(value & DMA_INTR_ENA_RIE)) { 207 x->rx_normal_irq_n++; 208 ret |= handle_rx; 209 } 210 } 211 if (likely(intr_status & DMA_STATUS_TI)) { 212 x->tx_normal_irq_n++; 213 ret |= handle_tx; 214 } 215 if (unlikely(intr_status & DMA_STATUS_ERI)) 216 x->rx_early_irq++; 217 } 218 /* Optional hardware blocks, interrupts should be disabled */ 219 if (unlikely(intr_status & 220 (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI))) 221 pr_warn("%s: unexpected status %08x\n", __func__, intr_status); 222 223 /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ 224 writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS); 225 226 return ret; 227 } 228 229 void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr) 230 { 231 u32 csr6 = readl(ioaddr + DMA_CONTROL); 232 writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL); 233 234 do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF)); 235 } 236 237 void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6], 238 unsigned int high, unsigned int low) 239 { 240 unsigned long data; 241 242 data = (addr[5] << 8) | addr[4]; 243 /* For MAC Addr registers we have to set the Address Enable (AE) 244 * bit that has no effect on the High Reg 0 where the bit 31 (MO) 245 * is RO. 246 */ 247 writel(data | GMAC_HI_REG_AE, ioaddr + high); 248 data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; 249 writel(data, ioaddr + low); 250 } 251 EXPORT_SYMBOL_GPL(stmmac_set_mac_addr); 252 253 /* Enable disable MAC RX/TX */ 254 void stmmac_set_mac(void __iomem *ioaddr, bool enable) 255 { 256 u32 value = readl(ioaddr + MAC_CTRL_REG); 257 258 if (enable) 259 value |= MAC_ENABLE_RX | MAC_ENABLE_TX; 260 else 261 value &= ~(MAC_ENABLE_TX | MAC_ENABLE_RX); 262 263 writel(value, ioaddr + MAC_CTRL_REG); 264 } 265 266 void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, 267 unsigned int high, unsigned int low) 268 { 269 unsigned int hi_addr, lo_addr; 270 271 /* Read the MAC address from the hardware */ 272 hi_addr = readl(ioaddr + high); 273 lo_addr = readl(ioaddr + low); 274 275 /* Extract the MAC address from the high and low words */ 276 addr[0] = lo_addr & 0xff; 277 addr[1] = (lo_addr >> 8) & 0xff; 278 addr[2] = (lo_addr >> 16) & 0xff; 279 addr[3] = (lo_addr >> 24) & 0xff; 280 addr[4] = hi_addr & 0xff; 281 addr[5] = (hi_addr >> 8) & 0xff; 282 } 283 EXPORT_SYMBOL_GPL(stmmac_get_mac_addr); 284