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(0));
  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(0));
  46}
  47
  48void dwmac4_dma_start_tx(void __iomem *ioaddr)
  49{
  50        u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(STMMAC_CHAN0));
  51
  52        value |= DMA_CONTROL_ST;
  53        writel(value, ioaddr + DMA_CHAN_TX_CONTROL(STMMAC_CHAN0));
  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)
  61{
  62        u32 value = readl(ioaddr + DMA_CHAN_TX_CONTROL(STMMAC_CHAN0));
  63
  64        value &= ~DMA_CONTROL_ST;
  65        writel(value, ioaddr + DMA_CHAN_TX_CONTROL(STMMAC_CHAN0));
  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)
  73{
  74        u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(STMMAC_CHAN0));
  75
  76        value |= DMA_CONTROL_SR;
  77
  78        writel(value, ioaddr + DMA_CHAN_RX_CONTROL(STMMAC_CHAN0));
  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)
  86{
  87        u32 value = readl(ioaddr + DMA_CHAN_RX_CONTROL(STMMAC_CHAN0));
  88
  89        value &= ~DMA_CONTROL_SR;
  90        writel(value, ioaddr + DMA_CHAN_RX_CONTROL(STMMAC_CHAN0));
  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)
  98{
  99        writel(len, ioaddr + DMA_CHAN_TX_RING_LEN(STMMAC_CHAN0));
 100}
 101
 102void dwmac4_set_rx_ring_len(void __iomem *ioaddr, u32 len)
 103{
 104        writel(len, ioaddr + DMA_CHAN_RX_RING_LEN(STMMAC_CHAN0));
 105}
 106
 107void dwmac4_enable_dma_irq(void __iomem *ioaddr)
 108{
 109        writel(DMA_CHAN_INTR_DEFAULT_MASK, ioaddr +
 110               DMA_CHAN_INTR_ENA(STMMAC_CHAN0));
 111}
 112
 113void dwmac410_enable_dma_irq(void __iomem *ioaddr)
 114{
 115        writel(DMA_CHAN_INTR_DEFAULT_MASK_4_10,
 116               ioaddr + DMA_CHAN_INTR_ENA(STMMAC_CHAN0));
 117}
 118
 119void dwmac4_disable_dma_irq(void __iomem *ioaddr)
 120{
 121        writel(0, ioaddr + DMA_CHAN_INTR_ENA(STMMAC_CHAN0));
 122}
 123
 124int dwmac4_dma_interrupt(void __iomem *ioaddr,
 125                         struct stmmac_extra_stats *x)
 126{
 127        int ret = 0;
 128
 129        u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(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                        u32 value;
 155
 156                        value = readl(ioaddr + DMA_CHAN_INTR_ENA(STMMAC_CHAN0));
 157                        /* to schedule NAPI on real RIE event. */
 158                        if (likely(value & DMA_CHAN_INTR_ENA_RIE)) {
 159                                x->rx_normal_irq_n++;
 160                                ret |= handle_rx;
 161                        }
 162                }
 163                if (likely(intr_status & DMA_CHAN_STATUS_TI)) {
 164                        x->tx_normal_irq_n++;
 165                        ret |= handle_tx;
 166                }
 167                if (unlikely(intr_status & DMA_CHAN_STATUS_ERI))
 168                        x->rx_early_irq++;
 169        }
 170
 171        /* Clear the interrupt by writing a logic 1 to the chanX interrupt
 172         * status [21-0] expect reserved bits [5-3]
 173         */
 174        writel((intr_status & 0x3fffc7),
 175               ioaddr + DMA_CHAN_STATUS(STMMAC_CHAN0));
 176
 177        return ret;
 178}
 179
 180void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
 181                                unsigned int high, unsigned int low)
 182{
 183        unsigned long data;
 184
 185        data = (addr[5] << 8) | addr[4];
 186        /* For MAC Addr registers se have to set the Address Enable (AE)
 187         * bit that has no effect on the High Reg 0 where the bit 31 (MO)
 188         * is RO.
 189         */
 190        data |= (STMMAC_CHAN0 << GMAC_HI_DCS_SHIFT);
 191        writel(data | GMAC_HI_REG_AE, ioaddr + high);
 192        data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
 193        writel(data, ioaddr + low);
 194}
 195
 196/* Enable disable MAC RX/TX */
 197void stmmac_dwmac4_set_mac(void __iomem *ioaddr, bool enable)
 198{
 199        u32 value = readl(ioaddr + GMAC_CONFIG);
 200
 201        if (enable)
 202                value |= GMAC_CONFIG_RE | GMAC_CONFIG_TE;
 203        else
 204                value &= ~(GMAC_CONFIG_TE | GMAC_CONFIG_RE);
 205
 206        writel(value, ioaddr + GMAC_CONFIG);
 207}
 208
 209void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
 210                                unsigned int high, unsigned int low)
 211{
 212        unsigned int hi_addr, lo_addr;
 213
 214        /* Read the MAC address from the hardware */
 215        hi_addr = readl(ioaddr + high);
 216        lo_addr = readl(ioaddr + low);
 217
 218        /* Extract the MAC address from the high and low words */
 219        addr[0] = lo_addr & 0xff;
 220        addr[1] = (lo_addr >> 8) & 0xff;
 221        addr[2] = (lo_addr >> 16) & 0xff;
 222        addr[3] = (lo_addr >> 24) & 0xff;
 223        addr[4] = hi_addr & 0xff;
 224        addr[5] = (hi_addr >> 8) & 0xff;
 225}
 226