xref: /openbmc/linux/drivers/dma/bestcomm/fec.c (revision 3bb16560)
1*3bb16560SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29a322993SPhilippe De Muyter /*
39a322993SPhilippe De Muyter  * Bestcomm FEC tasks driver
49a322993SPhilippe De Muyter  *
59a322993SPhilippe De Muyter  * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>
69a322993SPhilippe De Muyter  * Copyright (C) 2003-2004 MontaVista, Software, Inc.
79a322993SPhilippe De Muyter  *                         ( by Dale Farnsworth <dfarnsworth@mvista.com> )
89a322993SPhilippe De Muyter  */
99a322993SPhilippe De Muyter 
109a322993SPhilippe De Muyter #include <linux/kernel.h>
119a322993SPhilippe De Muyter #include <linux/module.h>
129a322993SPhilippe De Muyter #include <linux/types.h>
139a322993SPhilippe De Muyter #include <asm/io.h>
149a322993SPhilippe De Muyter 
159a322993SPhilippe De Muyter #include <linux/fsl/bestcomm/bestcomm.h>
169a322993SPhilippe De Muyter #include <linux/fsl/bestcomm/bestcomm_priv.h>
179a322993SPhilippe De Muyter #include <linux/fsl/bestcomm/fec.h>
189a322993SPhilippe De Muyter 
199a322993SPhilippe De Muyter 
209a322993SPhilippe De Muyter /* ======================================================================== */
219a322993SPhilippe De Muyter /* Task image/var/inc                                                       */
229a322993SPhilippe De Muyter /* ======================================================================== */
239a322993SPhilippe De Muyter 
249a322993SPhilippe De Muyter /* fec tasks images */
259a322993SPhilippe De Muyter extern u32 bcom_fec_rx_task[];
269a322993SPhilippe De Muyter extern u32 bcom_fec_tx_task[];
279a322993SPhilippe De Muyter 
289a322993SPhilippe De Muyter /* rx task vars that need to be set before enabling the task */
299a322993SPhilippe De Muyter struct bcom_fec_rx_var {
309a322993SPhilippe De Muyter 	u32 enable;		/* (u16*) address of task's control register */
319a322993SPhilippe De Muyter 	u32 fifo;		/* (u32*) address of fec's fifo */
329a322993SPhilippe De Muyter 	u32 bd_base;		/* (struct bcom_bd*) beginning of ring buffer */
339a322993SPhilippe De Muyter 	u32 bd_last;		/* (struct bcom_bd*) end of ring buffer */
349a322993SPhilippe De Muyter 	u32 bd_start;		/* (struct bcom_bd*) current bd */
359a322993SPhilippe De Muyter 	u32 buffer_size;	/* size of receive buffer */
369a322993SPhilippe De Muyter };
379a322993SPhilippe De Muyter 
389a322993SPhilippe De Muyter /* rx task incs that need to be set before enabling the task */
399a322993SPhilippe De Muyter struct bcom_fec_rx_inc {
409a322993SPhilippe De Muyter 	u16 pad0;
419a322993SPhilippe De Muyter 	s16 incr_bytes;
429a322993SPhilippe De Muyter 	u16 pad1;
439a322993SPhilippe De Muyter 	s16 incr_dst;
449a322993SPhilippe De Muyter 	u16 pad2;
459a322993SPhilippe De Muyter 	s16 incr_dst_ma;
469a322993SPhilippe De Muyter };
479a322993SPhilippe De Muyter 
489a322993SPhilippe De Muyter /* tx task vars that need to be set before enabling the task */
499a322993SPhilippe De Muyter struct bcom_fec_tx_var {
509a322993SPhilippe De Muyter 	u32 DRD;		/* (u32*) address of self-modified DRD */
519a322993SPhilippe De Muyter 	u32 fifo;		/* (u32*) address of fec's fifo */
529a322993SPhilippe De Muyter 	u32 enable;		/* (u16*) address of task's control register */
539a322993SPhilippe De Muyter 	u32 bd_base;		/* (struct bcom_bd*) beginning of ring buffer */
549a322993SPhilippe De Muyter 	u32 bd_last;		/* (struct bcom_bd*) end of ring buffer */
559a322993SPhilippe De Muyter 	u32 bd_start;		/* (struct bcom_bd*) current bd */
569a322993SPhilippe De Muyter 	u32 buffer_size;	/* set by uCode for each packet */
579a322993SPhilippe De Muyter };
589a322993SPhilippe De Muyter 
599a322993SPhilippe De Muyter /* tx task incs that need to be set before enabling the task */
609a322993SPhilippe De Muyter struct bcom_fec_tx_inc {
619a322993SPhilippe De Muyter 	u16 pad0;
629a322993SPhilippe De Muyter 	s16 incr_bytes;
639a322993SPhilippe De Muyter 	u16 pad1;
649a322993SPhilippe De Muyter 	s16 incr_src;
659a322993SPhilippe De Muyter 	u16 pad2;
669a322993SPhilippe De Muyter 	s16 incr_src_ma;
679a322993SPhilippe De Muyter };
689a322993SPhilippe De Muyter 
699a322993SPhilippe De Muyter /* private structure in the task */
709a322993SPhilippe De Muyter struct bcom_fec_priv {
719a322993SPhilippe De Muyter 	phys_addr_t	fifo;
729a322993SPhilippe De Muyter 	int		maxbufsize;
739a322993SPhilippe De Muyter };
749a322993SPhilippe De Muyter 
759a322993SPhilippe De Muyter 
769a322993SPhilippe De Muyter /* ======================================================================== */
779a322993SPhilippe De Muyter /* Task support code                                                        */
789a322993SPhilippe De Muyter /* ======================================================================== */
799a322993SPhilippe De Muyter 
809a322993SPhilippe De Muyter struct bcom_task *
bcom_fec_rx_init(int queue_len,phys_addr_t fifo,int maxbufsize)819a322993SPhilippe De Muyter bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize)
829a322993SPhilippe De Muyter {
839a322993SPhilippe De Muyter 	struct bcom_task *tsk;
849a322993SPhilippe De Muyter 	struct bcom_fec_priv *priv;
859a322993SPhilippe De Muyter 
869a322993SPhilippe De Muyter 	tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
879a322993SPhilippe De Muyter 				sizeof(struct bcom_fec_priv));
889a322993SPhilippe De Muyter 	if (!tsk)
899a322993SPhilippe De Muyter 		return NULL;
909a322993SPhilippe De Muyter 
919a322993SPhilippe De Muyter 	tsk->flags = BCOM_FLAGS_NONE;
929a322993SPhilippe De Muyter 
939a322993SPhilippe De Muyter 	priv = tsk->priv;
949a322993SPhilippe De Muyter 	priv->fifo = fifo;
959a322993SPhilippe De Muyter 	priv->maxbufsize = maxbufsize;
969a322993SPhilippe De Muyter 
979a322993SPhilippe De Muyter 	if (bcom_fec_rx_reset(tsk)) {
989a322993SPhilippe De Muyter 		bcom_task_free(tsk);
999a322993SPhilippe De Muyter 		return NULL;
1009a322993SPhilippe De Muyter 	}
1019a322993SPhilippe De Muyter 
1029a322993SPhilippe De Muyter 	return tsk;
1039a322993SPhilippe De Muyter }
1049a322993SPhilippe De Muyter EXPORT_SYMBOL_GPL(bcom_fec_rx_init);
1059a322993SPhilippe De Muyter 
1069a322993SPhilippe De Muyter int
bcom_fec_rx_reset(struct bcom_task * tsk)1079a322993SPhilippe De Muyter bcom_fec_rx_reset(struct bcom_task *tsk)
1089a322993SPhilippe De Muyter {
1099a322993SPhilippe De Muyter 	struct bcom_fec_priv *priv = tsk->priv;
1109a322993SPhilippe De Muyter 	struct bcom_fec_rx_var *var;
1119a322993SPhilippe De Muyter 	struct bcom_fec_rx_inc *inc;
1129a322993SPhilippe De Muyter 
1139a322993SPhilippe De Muyter 	/* Shutdown the task */
1149a322993SPhilippe De Muyter 	bcom_disable_task(tsk->tasknum);
1159a322993SPhilippe De Muyter 
1169a322993SPhilippe De Muyter 	/* Reset the microcode */
1179a322993SPhilippe De Muyter 	var = (struct bcom_fec_rx_var *) bcom_task_var(tsk->tasknum);
1189a322993SPhilippe De Muyter 	inc = (struct bcom_fec_rx_inc *) bcom_task_inc(tsk->tasknum);
1199a322993SPhilippe De Muyter 
1209a322993SPhilippe De Muyter 	if (bcom_load_image(tsk->tasknum, bcom_fec_rx_task))
1219a322993SPhilippe De Muyter 		return -1;
1229a322993SPhilippe De Muyter 
1239a322993SPhilippe De Muyter 	var->enable	= bcom_eng->regs_base +
1249a322993SPhilippe De Muyter 				offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
1259a322993SPhilippe De Muyter 	var->fifo	= (u32) priv->fifo;
1269a322993SPhilippe De Muyter 	var->bd_base	= tsk->bd_pa;
1279a322993SPhilippe De Muyter 	var->bd_last	= tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
1289a322993SPhilippe De Muyter 	var->bd_start	= tsk->bd_pa;
1299a322993SPhilippe De Muyter 	var->buffer_size = priv->maxbufsize;
1309a322993SPhilippe De Muyter 
1319a322993SPhilippe De Muyter 	inc->incr_bytes	= -(s16)sizeof(u32);	/* These should be in the   */
1329a322993SPhilippe De Muyter 	inc->incr_dst	= sizeof(u32);		/* task image, but we stick */
1339a322993SPhilippe De Muyter 	inc->incr_dst_ma= sizeof(u8);		/* to the official ones     */
1349a322993SPhilippe De Muyter 
1359a322993SPhilippe De Muyter 	/* Reset the BDs */
1369a322993SPhilippe De Muyter 	tsk->index = 0;
1379a322993SPhilippe De Muyter 	tsk->outdex = 0;
1389a322993SPhilippe De Muyter 
139adec566bSAnatolij Gustschin 	memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
1409a322993SPhilippe De Muyter 
1419a322993SPhilippe De Muyter 	/* Configure some stuff */
1429a322993SPhilippe De Muyter 	bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA);
1439a322993SPhilippe De Muyter 	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
1449a322993SPhilippe De Muyter 
1459a322993SPhilippe De Muyter 	out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX);
1469a322993SPhilippe De Muyter 
1479a322993SPhilippe De Muyter 	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
1489a322993SPhilippe De Muyter 
1499a322993SPhilippe De Muyter 	return 0;
1509a322993SPhilippe De Muyter }
1519a322993SPhilippe De Muyter EXPORT_SYMBOL_GPL(bcom_fec_rx_reset);
1529a322993SPhilippe De Muyter 
1539a322993SPhilippe De Muyter void
bcom_fec_rx_release(struct bcom_task * tsk)1549a322993SPhilippe De Muyter bcom_fec_rx_release(struct bcom_task *tsk)
1559a322993SPhilippe De Muyter {
1569a322993SPhilippe De Muyter 	/* Nothing special for the FEC tasks */
1579a322993SPhilippe De Muyter 	bcom_task_free(tsk);
1589a322993SPhilippe De Muyter }
1599a322993SPhilippe De Muyter EXPORT_SYMBOL_GPL(bcom_fec_rx_release);
1609a322993SPhilippe De Muyter 
1619a322993SPhilippe De Muyter 
1629a322993SPhilippe De Muyter 
1639a322993SPhilippe De Muyter 	/* Return 2nd to last DRD */
1649a322993SPhilippe De Muyter 	/* This is an ugly hack, but at least it's only done
1659a322993SPhilippe De Muyter 	   once at initialization */
self_modified_drd(int tasknum)1669a322993SPhilippe De Muyter static u32 *self_modified_drd(int tasknum)
1679a322993SPhilippe De Muyter {
1689a322993SPhilippe De Muyter 	u32 *desc;
1699a322993SPhilippe De Muyter 	int num_descs;
1709a322993SPhilippe De Muyter 	int drd_count;
1719a322993SPhilippe De Muyter 	int i;
1729a322993SPhilippe De Muyter 
1739a322993SPhilippe De Muyter 	num_descs = bcom_task_num_descs(tasknum);
1749a322993SPhilippe De Muyter 	desc = bcom_task_desc(tasknum) + num_descs - 1;
1759a322993SPhilippe De Muyter 	drd_count = 0;
1769a322993SPhilippe De Muyter 	for (i=0; i<num_descs; i++, desc--)
1779a322993SPhilippe De Muyter 		if (bcom_desc_is_drd(*desc) && ++drd_count == 3)
1789a322993SPhilippe De Muyter 			break;
1799a322993SPhilippe De Muyter 	return desc;
1809a322993SPhilippe De Muyter }
1819a322993SPhilippe De Muyter 
1829a322993SPhilippe De Muyter struct bcom_task *
bcom_fec_tx_init(int queue_len,phys_addr_t fifo)1839a322993SPhilippe De Muyter bcom_fec_tx_init(int queue_len, phys_addr_t fifo)
1849a322993SPhilippe De Muyter {
1859a322993SPhilippe De Muyter 	struct bcom_task *tsk;
1869a322993SPhilippe De Muyter 	struct bcom_fec_priv *priv;
1879a322993SPhilippe De Muyter 
1889a322993SPhilippe De Muyter 	tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),
1899a322993SPhilippe De Muyter 				sizeof(struct bcom_fec_priv));
1909a322993SPhilippe De Muyter 	if (!tsk)
1919a322993SPhilippe De Muyter 		return NULL;
1929a322993SPhilippe De Muyter 
1939a322993SPhilippe De Muyter 	tsk->flags = BCOM_FLAGS_ENABLE_TASK;
1949a322993SPhilippe De Muyter 
1959a322993SPhilippe De Muyter 	priv = tsk->priv;
1969a322993SPhilippe De Muyter 	priv->fifo = fifo;
1979a322993SPhilippe De Muyter 
1989a322993SPhilippe De Muyter 	if (bcom_fec_tx_reset(tsk)) {
1999a322993SPhilippe De Muyter 		bcom_task_free(tsk);
2009a322993SPhilippe De Muyter 		return NULL;
2019a322993SPhilippe De Muyter 	}
2029a322993SPhilippe De Muyter 
2039a322993SPhilippe De Muyter 	return tsk;
2049a322993SPhilippe De Muyter }
2059a322993SPhilippe De Muyter EXPORT_SYMBOL_GPL(bcom_fec_tx_init);
2069a322993SPhilippe De Muyter 
2079a322993SPhilippe De Muyter int
bcom_fec_tx_reset(struct bcom_task * tsk)2089a322993SPhilippe De Muyter bcom_fec_tx_reset(struct bcom_task *tsk)
2099a322993SPhilippe De Muyter {
2109a322993SPhilippe De Muyter 	struct bcom_fec_priv *priv = tsk->priv;
2119a322993SPhilippe De Muyter 	struct bcom_fec_tx_var *var;
2129a322993SPhilippe De Muyter 	struct bcom_fec_tx_inc *inc;
2139a322993SPhilippe De Muyter 
2149a322993SPhilippe De Muyter 	/* Shutdown the task */
2159a322993SPhilippe De Muyter 	bcom_disable_task(tsk->tasknum);
2169a322993SPhilippe De Muyter 
2179a322993SPhilippe De Muyter 	/* Reset the microcode */
2189a322993SPhilippe De Muyter 	var = (struct bcom_fec_tx_var *) bcom_task_var(tsk->tasknum);
2199a322993SPhilippe De Muyter 	inc = (struct bcom_fec_tx_inc *) bcom_task_inc(tsk->tasknum);
2209a322993SPhilippe De Muyter 
2219a322993SPhilippe De Muyter 	if (bcom_load_image(tsk->tasknum, bcom_fec_tx_task))
2229a322993SPhilippe De Muyter 		return -1;
2239a322993SPhilippe De Muyter 
2249a322993SPhilippe De Muyter 	var->enable	= bcom_eng->regs_base +
2259a322993SPhilippe De Muyter 				offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);
2269a322993SPhilippe De Muyter 	var->fifo	= (u32) priv->fifo;
2279a322993SPhilippe De Muyter 	var->DRD	= bcom_sram_va2pa(self_modified_drd(tsk->tasknum));
2289a322993SPhilippe De Muyter 	var->bd_base	= tsk->bd_pa;
2299a322993SPhilippe De Muyter 	var->bd_last	= tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);
2309a322993SPhilippe De Muyter 	var->bd_start	= tsk->bd_pa;
2319a322993SPhilippe De Muyter 
2329a322993SPhilippe De Muyter 	inc->incr_bytes	= -(s16)sizeof(u32);	/* These should be in the   */
2339a322993SPhilippe De Muyter 	inc->incr_src	= sizeof(u32);		/* task image, but we stick */
2349a322993SPhilippe De Muyter 	inc->incr_src_ma= sizeof(u8);		/* to the official ones     */
2359a322993SPhilippe De Muyter 
2369a322993SPhilippe De Muyter 	/* Reset the BDs */
2379a322993SPhilippe De Muyter 	tsk->index = 0;
2389a322993SPhilippe De Muyter 	tsk->outdex = 0;
2399a322993SPhilippe De Muyter 
240adec566bSAnatolij Gustschin 	memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);
2419a322993SPhilippe De Muyter 
2429a322993SPhilippe De Muyter 	/* Configure some stuff */
2439a322993SPhilippe De Muyter 	bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA);
2449a322993SPhilippe De Muyter 	bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);
2459a322993SPhilippe De Muyter 
2469a322993SPhilippe De Muyter 	out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX);
2479a322993SPhilippe De Muyter 
2489a322993SPhilippe De Muyter 	out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum);	/* Clear ints */
2499a322993SPhilippe De Muyter 
2509a322993SPhilippe De Muyter 	return 0;
2519a322993SPhilippe De Muyter }
2529a322993SPhilippe De Muyter EXPORT_SYMBOL_GPL(bcom_fec_tx_reset);
2539a322993SPhilippe De Muyter 
2549a322993SPhilippe De Muyter void
bcom_fec_tx_release(struct bcom_task * tsk)2559a322993SPhilippe De Muyter bcom_fec_tx_release(struct bcom_task *tsk)
2569a322993SPhilippe De Muyter {
2579a322993SPhilippe De Muyter 	/* Nothing special for the FEC tasks */
2589a322993SPhilippe De Muyter 	bcom_task_free(tsk);
2599a322993SPhilippe De Muyter }
2609a322993SPhilippe De Muyter EXPORT_SYMBOL_GPL(bcom_fec_tx_release);
2619a322993SPhilippe De Muyter 
2629a322993SPhilippe De Muyter 
2639a322993SPhilippe De Muyter MODULE_DESCRIPTION("BestComm FEC tasks driver");
2649a322993SPhilippe De Muyter MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
2659a322993SPhilippe De Muyter MODULE_LICENSE("GPL v2");
266