1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2007-2015 STMicroelectronics Ltd 4 * 5 * Author: Alexandre Torgue <alexandre.torgue@st.com> 6 */ 7 8 #include <linux/io.h> 9 #include <linux/iopoll.h> 10 #include <linux/delay.h> 11 #include "common.h" 12 #include "dwmac4_dma.h" 13 #include "dwmac4.h" 14 #include "stmmac.h" 15 16 int dwmac4_dma_reset(void __iomem *ioaddr) 17 { 18 u32 value = readl(ioaddr + DMA_BUS_MODE); 19 20 /* DMA SW reset */ 21 value |= DMA_BUS_MODE_SFT_RESET; 22 writel(value, ioaddr + DMA_BUS_MODE); 23 24 return readl_poll_timeout(ioaddr + DMA_BUS_MODE, value, 25 !(value & DMA_BUS_MODE_SFT_RESET), 26 10000, 1000000); 27 } 28 29 void dwmac4_set_rx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr, 30 u32 tail_ptr, u32 chan) 31 { 32 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 33 34 writel(tail_ptr, ioaddr + DMA_CHAN_RX_END_ADDR(dwmac4_addrs, chan)); 35 } 36 37 void dwmac4_set_tx_tail_ptr(struct stmmac_priv *priv, void __iomem *ioaddr, 38 u32 tail_ptr, u32 chan) 39 { 40 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 41 42 writel(tail_ptr, ioaddr + DMA_CHAN_TX_END_ADDR(dwmac4_addrs, chan)); 43 } 44 45 void dwmac4_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr, 46 u32 chan) 47 { 48 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 49 u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan)); 50 51 value |= DMA_CONTROL_ST; 52 writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan)); 53 54 value = readl(ioaddr + GMAC_CONFIG); 55 value |= GMAC_CONFIG_TE; 56 writel(value, ioaddr + GMAC_CONFIG); 57 } 58 59 void dwmac4_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr, 60 u32 chan) 61 { 62 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 63 64 u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan)); 65 66 value &= ~DMA_CONTROL_ST; 67 writel(value, ioaddr + DMA_CHAN_TX_CONTROL(dwmac4_addrs, chan)); 68 } 69 70 void dwmac4_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr, 71 u32 chan) 72 { 73 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 74 75 u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan)); 76 77 value |= DMA_CONTROL_SR; 78 79 writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan)); 80 81 value = readl(ioaddr + GMAC_CONFIG); 82 value |= GMAC_CONFIG_RE; 83 writel(value, ioaddr + GMAC_CONFIG); 84 } 85 86 void dwmac4_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr, 87 u32 chan) 88 { 89 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 90 u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan)); 91 92 value &= ~DMA_CONTROL_SR; 93 writel(value, ioaddr + DMA_CHAN_RX_CONTROL(dwmac4_addrs, chan)); 94 } 95 96 void dwmac4_set_tx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr, 97 u32 len, u32 chan) 98 { 99 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 100 101 writel(len, ioaddr + DMA_CHAN_TX_RING_LEN(dwmac4_addrs, chan)); 102 } 103 104 void dwmac4_set_rx_ring_len(struct stmmac_priv *priv, void __iomem *ioaddr, 105 u32 len, u32 chan) 106 { 107 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 108 109 writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(dwmac4_addrs, chan)); 110 } 111 112 void dwmac4_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, 113 u32 chan, bool rx, bool tx) 114 { 115 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 116 u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 117 118 if (rx) 119 value |= DMA_CHAN_INTR_DEFAULT_RX; 120 if (tx) 121 value |= DMA_CHAN_INTR_DEFAULT_TX; 122 123 writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 124 } 125 126 void dwmac410_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, 127 u32 chan, bool rx, bool tx) 128 { 129 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 130 u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 131 132 if (rx) 133 value |= DMA_CHAN_INTR_DEFAULT_RX_4_10; 134 if (tx) 135 value |= DMA_CHAN_INTR_DEFAULT_TX_4_10; 136 137 writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 138 } 139 140 void dwmac4_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, 141 u32 chan, bool rx, bool tx) 142 { 143 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 144 u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 145 146 if (rx) 147 value &= ~DMA_CHAN_INTR_DEFAULT_RX; 148 if (tx) 149 value &= ~DMA_CHAN_INTR_DEFAULT_TX; 150 151 writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 152 } 153 154 void dwmac410_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, 155 u32 chan, bool rx, bool tx) 156 { 157 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 158 u32 value = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 159 160 if (rx) 161 value &= ~DMA_CHAN_INTR_DEFAULT_RX_4_10; 162 if (tx) 163 value &= ~DMA_CHAN_INTR_DEFAULT_TX_4_10; 164 165 writel(value, ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 166 } 167 168 int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, 169 struct stmmac_extra_stats *x, u32 chan, u32 dir) 170 { 171 const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; 172 u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan)); 173 u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); 174 int ret = 0; 175 176 if (dir == DMA_DIR_RX) 177 intr_status &= DMA_CHAN_STATUS_MSK_RX; 178 else if (dir == DMA_DIR_TX) 179 intr_status &= DMA_CHAN_STATUS_MSK_TX; 180 181 /* ABNORMAL interrupts */ 182 if (unlikely(intr_status & DMA_CHAN_STATUS_AIS)) { 183 if (unlikely(intr_status & DMA_CHAN_STATUS_RBU)) 184 x->rx_buf_unav_irq++; 185 if (unlikely(intr_status & DMA_CHAN_STATUS_RPS)) 186 x->rx_process_stopped_irq++; 187 if (unlikely(intr_status & DMA_CHAN_STATUS_RWT)) 188 x->rx_watchdog_irq++; 189 if (unlikely(intr_status & DMA_CHAN_STATUS_ETI)) 190 x->tx_early_irq++; 191 if (unlikely(intr_status & DMA_CHAN_STATUS_TPS)) { 192 x->tx_process_stopped_irq++; 193 ret = tx_hard_error; 194 } 195 if (unlikely(intr_status & DMA_CHAN_STATUS_FBE)) { 196 x->fatal_bus_error_irq++; 197 ret = tx_hard_error; 198 } 199 } 200 /* TX/RX NORMAL interrupts */ 201 if (likely(intr_status & DMA_CHAN_STATUS_NIS)) 202 x->normal_irq_n++; 203 if (likely(intr_status & DMA_CHAN_STATUS_RI)) { 204 x->rx_normal_irq_n++; 205 x->rxq_stats[chan].rx_normal_irq_n++; 206 ret |= handle_rx; 207 } 208 if (likely(intr_status & DMA_CHAN_STATUS_TI)) { 209 x->tx_normal_irq_n++; 210 x->txq_stats[chan].tx_normal_irq_n++; 211 ret |= handle_tx; 212 } 213 if (unlikely(intr_status & DMA_CHAN_STATUS_TBU)) 214 ret |= handle_tx; 215 if (unlikely(intr_status & DMA_CHAN_STATUS_ERI)) 216 x->rx_early_irq++; 217 218 writel(intr_status & intr_en, 219 ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan)); 220 return ret; 221 } 222 223 void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, const u8 addr[6], 224 unsigned int high, unsigned int low) 225 { 226 unsigned long data; 227 228 data = (addr[5] << 8) | addr[4]; 229 /* For MAC Addr registers se have to set the Address Enable (AE) 230 * bit that has no effect on the High Reg 0 where the bit 31 (MO) 231 * is RO. 232 */ 233 data |= (STMMAC_CHAN0 << GMAC_HI_DCS_SHIFT); 234 writel(data | GMAC_HI_REG_AE, ioaddr + high); 235 data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; 236 writel(data, ioaddr + low); 237 } 238 239 /* Enable disable MAC RX/TX */ 240 void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable) 241 { 242 u32 value = readl(ioaddr + GMAC_CONFIG); 243 244 if (enable) 245 value |= GMAC_CONFIG_RE | GMAC_CONFIG_TE; 246 else 247 value &= ~(GMAC_CONFIG_TE | GMAC_CONFIG_RE); 248 249 writel(value, ioaddr + GMAC_CONFIG); 250 } 251 252 void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr, 253 unsigned int high, unsigned int low) 254 { 255 unsigned int hi_addr, lo_addr; 256 257 /* Read the MAC address from the hardware */ 258 hi_addr = readl(ioaddr + high); 259 lo_addr = readl(ioaddr + low); 260 261 /* Extract the MAC address from the high and low words */ 262 addr[0] = lo_addr & 0xff; 263 addr[1] = (lo_addr >> 8) & 0xff; 264 addr[2] = (lo_addr >> 16) & 0xff; 265 addr[3] = (lo_addr >> 24) & 0xff; 266 addr[4] = hi_addr & 0xff; 267 addr[5] = (hi_addr >> 8) & 0xff; 268 } 269