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