1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /******************************************************************************* |
3 | This is the driver for the MAC 10/100 on-chip Ethernet controller |
4 | currently tested on all the ST boards based on STb7109 and stx7200 SoCs. |
5 | |
6 | DWC Ether MAC 10/100 Universal version 4.0 has been used for developing |
7 | this code. |
8 | |
9 | This contains the functions to handle the dma. |
10 | |
11 | Copyright (C) 2007-2009 STMicroelectronics Ltd |
12 | |
13 | |
14 | Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> |
15 | *******************************************************************************/ |
16 | |
17 | #include <asm/io.h> |
18 | #include "dwmac100.h" |
19 | #include "dwmac_dma.h" |
20 | |
21 | static void dwmac100_dma_init(void __iomem *ioaddr, |
22 | struct stmmac_dma_cfg *dma_cfg, int atds) |
23 | { |
24 | /* Enable Application Access by writing to DMA CSR0 */ |
25 | writel(DMA_BUS_MODE_DEFAULT | (dma_cfg->pbl << DMA_BUS_MODE_PBL_SHIFT), |
26 | addr: ioaddr + DMA_BUS_MODE); |
27 | |
28 | /* Mask interrupts by writing to CSR7 */ |
29 | writel(DMA_INTR_DEFAULT_MASK, addr: ioaddr + DMA_INTR_ENA); |
30 | } |
31 | |
32 | static void dwmac100_dma_init_rx(struct stmmac_priv *priv, void __iomem *ioaddr, |
33 | struct stmmac_dma_cfg *dma_cfg, |
34 | dma_addr_t dma_rx_phy, u32 chan) |
35 | { |
36 | /* RX descriptor base addr lists must be written into DMA CSR3 */ |
37 | writel(lower_32_bits(dma_rx_phy), addr: ioaddr + DMA_RCV_BASE_ADDR); |
38 | } |
39 | |
40 | static void dwmac100_dma_init_tx(struct stmmac_priv *priv, void __iomem *ioaddr, |
41 | struct stmmac_dma_cfg *dma_cfg, |
42 | dma_addr_t dma_tx_phy, u32 chan) |
43 | { |
44 | /* TX descriptor base addr lists must be written into DMA CSR4 */ |
45 | writel(lower_32_bits(dma_tx_phy), addr: ioaddr + DMA_TX_BASE_ADDR); |
46 | } |
47 | |
48 | /* Store and Forward capability is not used at all. |
49 | * |
50 | * The transmit threshold can be programmed by setting the TTC bits in the DMA |
51 | * control register. |
52 | */ |
53 | static void dwmac100_dma_operation_mode_tx(struct stmmac_priv *priv, |
54 | void __iomem *ioaddr, int mode, |
55 | u32 channel, int fifosz, u8 qmode) |
56 | { |
57 | u32 csr6 = readl(addr: ioaddr + DMA_CONTROL); |
58 | |
59 | if (mode <= 32) |
60 | csr6 |= DMA_CONTROL_TTC_32; |
61 | else if (mode <= 64) |
62 | csr6 |= DMA_CONTROL_TTC_64; |
63 | else |
64 | csr6 |= DMA_CONTROL_TTC_128; |
65 | |
66 | writel(val: csr6, addr: ioaddr + DMA_CONTROL); |
67 | } |
68 | |
69 | static void dwmac100_dump_dma_regs(struct stmmac_priv *priv, |
70 | void __iomem *ioaddr, u32 *reg_space) |
71 | { |
72 | int i; |
73 | |
74 | for (i = 0; i < NUM_DWMAC100_DMA_REGS; i++) |
75 | reg_space[DMA_BUS_MODE / 4 + i] = |
76 | readl(addr: ioaddr + DMA_BUS_MODE + i * 4); |
77 | |
78 | reg_space[DMA_CUR_TX_BUF_ADDR / 4] = |
79 | readl(addr: ioaddr + DMA_CUR_TX_BUF_ADDR); |
80 | reg_space[DMA_CUR_RX_BUF_ADDR / 4] = |
81 | readl(addr: ioaddr + DMA_CUR_RX_BUF_ADDR); |
82 | } |
83 | |
84 | /* DMA controller has two counters to track the number of the missed frames. */ |
85 | static void dwmac100_dma_diagnostic_fr(struct stmmac_extra_stats *x, |
86 | void __iomem *ioaddr) |
87 | { |
88 | u32 csr8 = readl(addr: ioaddr + DMA_MISSED_FRAME_CTR); |
89 | |
90 | if (unlikely(csr8)) { |
91 | if (csr8 & DMA_MISSED_FRAME_OVE) { |
92 | x->rx_overflow_cntr += 0x800; |
93 | } else { |
94 | unsigned int ove_cntr; |
95 | ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17); |
96 | x->rx_overflow_cntr += ove_cntr; |
97 | } |
98 | |
99 | if (csr8 & DMA_MISSED_FRAME_OVE_M) { |
100 | x->rx_missed_cntr += 0xffff; |
101 | } else { |
102 | unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR); |
103 | x->rx_missed_cntr += miss_f; |
104 | } |
105 | } |
106 | } |
107 | |
108 | const struct stmmac_dma_ops dwmac100_dma_ops = { |
109 | .reset = dwmac_dma_reset, |
110 | .init = dwmac100_dma_init, |
111 | .init_rx_chan = dwmac100_dma_init_rx, |
112 | .init_tx_chan = dwmac100_dma_init_tx, |
113 | .dump_regs = dwmac100_dump_dma_regs, |
114 | .dma_tx_mode = dwmac100_dma_operation_mode_tx, |
115 | .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr, |
116 | .enable_dma_transmission = dwmac_enable_dma_transmission, |
117 | .enable_dma_irq = dwmac_enable_dma_irq, |
118 | .disable_dma_irq = dwmac_disable_dma_irq, |
119 | .start_tx = dwmac_dma_start_tx, |
120 | .stop_tx = dwmac_dma_stop_tx, |
121 | .start_rx = dwmac_dma_start_rx, |
122 | .stop_rx = dwmac_dma_stop_rx, |
123 | .dma_interrupt = dwmac_dma_interrupt, |
124 | }; |
125 | |