14fa9c49fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27ac6653aSJeff Kirsher /*******************************************************************************
37ac6653aSJeff Kirsher   This is the driver for the MAC 10/100 on-chip Ethernet controller
47ac6653aSJeff Kirsher   currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
57ac6653aSJeff Kirsher 
67ac6653aSJeff Kirsher   DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
77ac6653aSJeff Kirsher   this code.
87ac6653aSJeff Kirsher 
97ac6653aSJeff Kirsher   This contains the functions to handle the dma.
107ac6653aSJeff Kirsher 
117ac6653aSJeff Kirsher   Copyright (C) 2007-2009  STMicroelectronics Ltd
127ac6653aSJeff Kirsher 
137ac6653aSJeff Kirsher 
147ac6653aSJeff Kirsher   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
157ac6653aSJeff Kirsher *******************************************************************************/
167ac6653aSJeff Kirsher 
177ac6653aSJeff Kirsher #include <asm/io.h>
187ac6653aSJeff Kirsher #include "dwmac100.h"
197ac6653aSJeff Kirsher #include "dwmac_dma.h"
207ac6653aSJeff Kirsher 
2150ca903aSNiklas Cassel static void dwmac100_dma_init(void __iomem *ioaddr,
2224aaed0cSJose Abreu 			      struct stmmac_dma_cfg *dma_cfg, int atds)
237ac6653aSJeff Kirsher {
247ac6653aSJeff Kirsher 	/* Enable Application Access by writing to DMA CSR0 */
2550ca903aSNiklas Cassel 	writel(DMA_BUS_MODE_DEFAULT | (dma_cfg->pbl << DMA_BUS_MODE_PBL_SHIFT),
267ac6653aSJeff Kirsher 	       ioaddr + DMA_BUS_MODE);
277ac6653aSJeff Kirsher 
287ac6653aSJeff Kirsher 	/* Mask interrupts by writing to CSR7 */
297ac6653aSJeff Kirsher 	writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
3024aaed0cSJose Abreu }
317ac6653aSJeff Kirsher 
3224aaed0cSJose Abreu static void dwmac100_dma_init_rx(void __iomem *ioaddr,
3324aaed0cSJose Abreu 				 struct stmmac_dma_cfg *dma_cfg,
3406a80a7dSJose Abreu 				 dma_addr_t dma_rx_phy, u32 chan)
3524aaed0cSJose Abreu {
3624aaed0cSJose Abreu 	/* RX descriptor base addr lists must be written into DMA CSR3 */
3706a80a7dSJose Abreu 	writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR);
3824aaed0cSJose Abreu }
3924aaed0cSJose Abreu 
4024aaed0cSJose Abreu static void dwmac100_dma_init_tx(void __iomem *ioaddr,
4124aaed0cSJose Abreu 				 struct stmmac_dma_cfg *dma_cfg,
4206a80a7dSJose Abreu 				 dma_addr_t dma_tx_phy, u32 chan)
4324aaed0cSJose Abreu {
4424aaed0cSJose Abreu 	/* TX descriptor base addr lists must be written into DMA CSR4 */
4506a80a7dSJose Abreu 	writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR);
467ac6653aSJeff Kirsher }
477ac6653aSJeff Kirsher 
48ceb69499SGiuseppe CAVALLARO /* Store and Forward capability is not used at all.
49ceb69499SGiuseppe CAVALLARO  *
50ceb69499SGiuseppe CAVALLARO  * The transmit threshold can be programmed by setting the TTC bits in the DMA
51ceb69499SGiuseppe CAVALLARO  * control register.
52ceb69499SGiuseppe CAVALLARO  */
53ab0204e3SJose Abreu static void dwmac100_dma_operation_mode_tx(void __iomem *ioaddr, int mode,
54ab0204e3SJose Abreu 					   u32 channel, int fifosz, u8 qmode)
557ac6653aSJeff Kirsher {
567ac6653aSJeff Kirsher 	u32 csr6 = readl(ioaddr + DMA_CONTROL);
577ac6653aSJeff Kirsher 
58ab0204e3SJose Abreu 	if (mode <= 32)
597ac6653aSJeff Kirsher 		csr6 |= DMA_CONTROL_TTC_32;
60ab0204e3SJose Abreu 	else if (mode <= 64)
617ac6653aSJeff Kirsher 		csr6 |= DMA_CONTROL_TTC_64;
627ac6653aSJeff Kirsher 	else
637ac6653aSJeff Kirsher 		csr6 |= DMA_CONTROL_TTC_128;
647ac6653aSJeff Kirsher 
657ac6653aSJeff Kirsher 	writel(csr6, ioaddr + DMA_CONTROL);
667ac6653aSJeff Kirsher }
677ac6653aSJeff Kirsher 
68fbf68229SLABBE Corentin static void dwmac100_dump_dma_regs(void __iomem *ioaddr, u32 *reg_space)
697ac6653aSJeff Kirsher {
707ac6653aSJeff Kirsher 	int i;
717ac6653aSJeff Kirsher 
72f4458b92SThor Thayer 	for (i = 0; i < NUM_DWMAC100_DMA_REGS; i++)
73fbf68229SLABBE Corentin 		reg_space[DMA_BUS_MODE / 4 + i] =
74fbf68229SLABBE Corentin 			readl(ioaddr + DMA_BUS_MODE + i * 4);
7583d7af64SGiuseppe CAVALLARO 
76fbf68229SLABBE Corentin 	reg_space[DMA_CUR_TX_BUF_ADDR / 4] =
77fbf68229SLABBE Corentin 		readl(ioaddr + DMA_CUR_TX_BUF_ADDR);
78fbf68229SLABBE Corentin 	reg_space[DMA_CUR_RX_BUF_ADDR / 4] =
79fbf68229SLABBE Corentin 		readl(ioaddr + DMA_CUR_RX_BUF_ADDR);
807ac6653aSJeff Kirsher }
817ac6653aSJeff Kirsher 
82ceb69499SGiuseppe CAVALLARO /* DMA controller has two counters to track the number of the missed frames. */
837ac6653aSJeff Kirsher static void dwmac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
847ac6653aSJeff Kirsher 				       void __iomem *ioaddr)
857ac6653aSJeff Kirsher {
867ac6653aSJeff Kirsher 	struct net_device_stats *stats = (struct net_device_stats *)data;
877ac6653aSJeff Kirsher 	u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
887ac6653aSJeff Kirsher 
897ac6653aSJeff Kirsher 	if (unlikely(csr8)) {
907ac6653aSJeff Kirsher 		if (csr8 & DMA_MISSED_FRAME_OVE) {
917ac6653aSJeff Kirsher 			stats->rx_over_errors += 0x800;
927ac6653aSJeff Kirsher 			x->rx_overflow_cntr += 0x800;
937ac6653aSJeff Kirsher 		} else {
947ac6653aSJeff Kirsher 			unsigned int ove_cntr;
957ac6653aSJeff Kirsher 			ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
967ac6653aSJeff Kirsher 			stats->rx_over_errors += ove_cntr;
977ac6653aSJeff Kirsher 			x->rx_overflow_cntr += ove_cntr;
987ac6653aSJeff Kirsher 		}
997ac6653aSJeff Kirsher 
1007ac6653aSJeff Kirsher 		if (csr8 & DMA_MISSED_FRAME_OVE_M) {
1017ac6653aSJeff Kirsher 			stats->rx_missed_errors += 0xffff;
1027ac6653aSJeff Kirsher 			x->rx_missed_cntr += 0xffff;
1037ac6653aSJeff Kirsher 		} else {
1047ac6653aSJeff Kirsher 			unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
1057ac6653aSJeff Kirsher 			stats->rx_missed_errors += miss_f;
1067ac6653aSJeff Kirsher 			x->rx_missed_cntr += miss_f;
1077ac6653aSJeff Kirsher 		}
1087ac6653aSJeff Kirsher 	}
1097ac6653aSJeff Kirsher }
1107ac6653aSJeff Kirsher 
1117ac6653aSJeff Kirsher const struct stmmac_dma_ops dwmac100_dma_ops = {
112495db273SGiuseppe Cavallaro 	.reset = dwmac_dma_reset,
1137ac6653aSJeff Kirsher 	.init = dwmac100_dma_init,
11424aaed0cSJose Abreu 	.init_rx_chan = dwmac100_dma_init_rx,
11524aaed0cSJose Abreu 	.init_tx_chan = dwmac100_dma_init_tx,
1167ac6653aSJeff Kirsher 	.dump_regs = dwmac100_dump_dma_regs,
117ab0204e3SJose Abreu 	.dma_tx_mode = dwmac100_dma_operation_mode_tx,
1187ac6653aSJeff Kirsher 	.dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
1197ac6653aSJeff Kirsher 	.enable_dma_transmission = dwmac_enable_dma_transmission,
1207ac6653aSJeff Kirsher 	.enable_dma_irq = dwmac_enable_dma_irq,
1217ac6653aSJeff Kirsher 	.disable_dma_irq = dwmac_disable_dma_irq,
1227ac6653aSJeff Kirsher 	.start_tx = dwmac_dma_start_tx,
1237ac6653aSJeff Kirsher 	.stop_tx = dwmac_dma_stop_tx,
1247ac6653aSJeff Kirsher 	.start_rx = dwmac_dma_start_rx,
1257ac6653aSJeff Kirsher 	.stop_rx = dwmac_dma_stop_rx,
1267ac6653aSJeff Kirsher 	.dma_interrupt = dwmac_dma_interrupt,
1277ac6653aSJeff Kirsher };
128