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