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