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 
dwmac100_dma_init(void __iomem * ioaddr,struct stmmac_dma_cfg * dma_cfg,int atds)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 
dwmac100_dma_init_rx(struct stmmac_priv * priv,void __iomem * ioaddr,struct stmmac_dma_cfg * dma_cfg,dma_addr_t dma_rx_phy,u32 chan)321d84b487SAndrew Halaney static void dwmac100_dma_init_rx(struct stmmac_priv *priv, 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 
dwmac100_dma_init_tx(struct stmmac_priv * priv,void __iomem * ioaddr,struct stmmac_dma_cfg * dma_cfg,dma_addr_t dma_tx_phy,u32 chan)401d84b487SAndrew Halaney static void dwmac100_dma_init_tx(struct stmmac_priv *priv, 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  */
dwmac100_dma_operation_mode_tx(struct stmmac_priv * priv,void __iomem * ioaddr,int mode,u32 channel,int fifosz,u8 qmode)531d84b487SAndrew Halaney static void dwmac100_dma_operation_mode_tx(struct stmmac_priv *priv,
541d84b487SAndrew Halaney 					   void __iomem *ioaddr, int mode,
55ab0204e3SJose Abreu 					   u32 channel, int fifosz, u8 qmode)
567ac6653aSJeff Kirsher {
577ac6653aSJeff Kirsher 	u32 csr6 = readl(ioaddr + DMA_CONTROL);
587ac6653aSJeff Kirsher 
59ab0204e3SJose Abreu 	if (mode <= 32)
607ac6653aSJeff Kirsher 		csr6 |= DMA_CONTROL_TTC_32;
61ab0204e3SJose Abreu 	else if (mode <= 64)
627ac6653aSJeff Kirsher 		csr6 |= DMA_CONTROL_TTC_64;
637ac6653aSJeff Kirsher 	else
647ac6653aSJeff Kirsher 		csr6 |= DMA_CONTROL_TTC_128;
657ac6653aSJeff Kirsher 
667ac6653aSJeff Kirsher 	writel(csr6, ioaddr + DMA_CONTROL);
677ac6653aSJeff Kirsher }
687ac6653aSJeff Kirsher 
dwmac100_dump_dma_regs(struct stmmac_priv * priv,void __iomem * ioaddr,u32 * reg_space)691d84b487SAndrew Halaney static void dwmac100_dump_dma_regs(struct stmmac_priv *priv,
701d84b487SAndrew Halaney 				   void __iomem *ioaddr, u32 *reg_space)
717ac6653aSJeff Kirsher {
727ac6653aSJeff Kirsher 	int i;
737ac6653aSJeff Kirsher 
74f4458b92SThor Thayer 	for (i = 0; i < NUM_DWMAC100_DMA_REGS; i++)
75fbf68229SLABBE Corentin 		reg_space[DMA_BUS_MODE / 4 + i] =
76fbf68229SLABBE Corentin 			readl(ioaddr + DMA_BUS_MODE + i * 4);
7783d7af64SGiuseppe CAVALLARO 
78fbf68229SLABBE Corentin 	reg_space[DMA_CUR_TX_BUF_ADDR / 4] =
79fbf68229SLABBE Corentin 		readl(ioaddr + DMA_CUR_TX_BUF_ADDR);
80fbf68229SLABBE Corentin 	reg_space[DMA_CUR_RX_BUF_ADDR / 4] =
81fbf68229SLABBE Corentin 		readl(ioaddr + DMA_CUR_RX_BUF_ADDR);
827ac6653aSJeff Kirsher }
837ac6653aSJeff Kirsher 
84ceb69499SGiuseppe CAVALLARO /* DMA controller has two counters to track the number of the missed frames. */
dwmac100_dma_diagnostic_fr(struct stmmac_extra_stats * x,void __iomem * ioaddr)85*133466c3SJisheng Zhang static void dwmac100_dma_diagnostic_fr(struct stmmac_extra_stats *x,
867ac6653aSJeff Kirsher 				       void __iomem *ioaddr)
877ac6653aSJeff Kirsher {
887ac6653aSJeff Kirsher 	u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
897ac6653aSJeff Kirsher 
907ac6653aSJeff Kirsher 	if (unlikely(csr8)) {
917ac6653aSJeff Kirsher 		if (csr8 & DMA_MISSED_FRAME_OVE) {
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 			x->rx_overflow_cntr += ove_cntr;
977ac6653aSJeff Kirsher 		}
987ac6653aSJeff Kirsher 
997ac6653aSJeff Kirsher 		if (csr8 & DMA_MISSED_FRAME_OVE_M) {
1007ac6653aSJeff Kirsher 			x->rx_missed_cntr += 0xffff;
1017ac6653aSJeff Kirsher 		} else {
1027ac6653aSJeff Kirsher 			unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
1037ac6653aSJeff Kirsher 			x->rx_missed_cntr += miss_f;
1047ac6653aSJeff Kirsher 		}
1057ac6653aSJeff Kirsher 	}
1067ac6653aSJeff Kirsher }
1077ac6653aSJeff Kirsher 
1087ac6653aSJeff Kirsher const struct stmmac_dma_ops dwmac100_dma_ops = {
109495db273SGiuseppe Cavallaro 	.reset = dwmac_dma_reset,
1107ac6653aSJeff Kirsher 	.init = dwmac100_dma_init,
11124aaed0cSJose Abreu 	.init_rx_chan = dwmac100_dma_init_rx,
11224aaed0cSJose Abreu 	.init_tx_chan = dwmac100_dma_init_tx,
1137ac6653aSJeff Kirsher 	.dump_regs = dwmac100_dump_dma_regs,
114ab0204e3SJose Abreu 	.dma_tx_mode = dwmac100_dma_operation_mode_tx,
1157ac6653aSJeff Kirsher 	.dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
1167ac6653aSJeff Kirsher 	.enable_dma_transmission = dwmac_enable_dma_transmission,
1177ac6653aSJeff Kirsher 	.enable_dma_irq = dwmac_enable_dma_irq,
1187ac6653aSJeff Kirsher 	.disable_dma_irq = dwmac_disable_dma_irq,
1197ac6653aSJeff Kirsher 	.start_tx = dwmac_dma_start_tx,
1207ac6653aSJeff Kirsher 	.stop_tx = dwmac_dma_stop_tx,
1217ac6653aSJeff Kirsher 	.start_rx = dwmac_dma_start_rx,
1227ac6653aSJeff Kirsher 	.stop_rx = dwmac_dma_stop_rx,
1237ac6653aSJeff Kirsher 	.dma_interrupt = dwmac_dma_interrupt,
1247ac6653aSJeff Kirsher };
125