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