266 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Bestcomm FEC tasks driver4 *5 * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com>6 * Copyright (C) 2003-2004 MontaVista, Software, Inc.7 * ( by Dale Farnsworth <dfarnsworth@mvista.com> )8 */9 10#include <linux/kernel.h>11#include <linux/module.h>12#include <linux/types.h>13#include <asm/io.h>14 15#include <linux/fsl/bestcomm/bestcomm.h>16#include <linux/fsl/bestcomm/bestcomm_priv.h>17#include <linux/fsl/bestcomm/fec.h>18 19 20/* ======================================================================== */21/* Task image/var/inc */22/* ======================================================================== */23 24/* fec tasks images */25extern u32 bcom_fec_rx_task[];26extern u32 bcom_fec_tx_task[];27 28/* rx task vars that need to be set before enabling the task */29struct bcom_fec_rx_var {30 u32 enable; /* (u16*) address of task's control register */31 u32 fifo; /* (u32*) address of fec's fifo */32 u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */33 u32 bd_last; /* (struct bcom_bd*) end of ring buffer */34 u32 bd_start; /* (struct bcom_bd*) current bd */35 u32 buffer_size; /* size of receive buffer */36};37 38/* rx task incs that need to be set before enabling the task */39struct bcom_fec_rx_inc {40 u16 pad0;41 s16 incr_bytes;42 u16 pad1;43 s16 incr_dst;44 u16 pad2;45 s16 incr_dst_ma;46};47 48/* tx task vars that need to be set before enabling the task */49struct bcom_fec_tx_var {50 u32 DRD; /* (u32*) address of self-modified DRD */51 u32 fifo; /* (u32*) address of fec's fifo */52 u32 enable; /* (u16*) address of task's control register */53 u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */54 u32 bd_last; /* (struct bcom_bd*) end of ring buffer */55 u32 bd_start; /* (struct bcom_bd*) current bd */56 u32 buffer_size; /* set by uCode for each packet */57};58 59/* tx task incs that need to be set before enabling the task */60struct bcom_fec_tx_inc {61 u16 pad0;62 s16 incr_bytes;63 u16 pad1;64 s16 incr_src;65 u16 pad2;66 s16 incr_src_ma;67};68 69/* private structure in the task */70struct bcom_fec_priv {71 phys_addr_t fifo;72 int maxbufsize;73};74 75 76/* ======================================================================== */77/* Task support code */78/* ======================================================================== */79 80struct bcom_task *81bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize)82{83 struct bcom_task *tsk;84 struct bcom_fec_priv *priv;85 86 tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),87 sizeof(struct bcom_fec_priv));88 if (!tsk)89 return NULL;90 91 tsk->flags = BCOM_FLAGS_NONE;92 93 priv = tsk->priv;94 priv->fifo = fifo;95 priv->maxbufsize = maxbufsize;96 97 if (bcom_fec_rx_reset(tsk)) {98 bcom_task_free(tsk);99 return NULL;100 }101 102 return tsk;103}104EXPORT_SYMBOL_GPL(bcom_fec_rx_init);105 106int107bcom_fec_rx_reset(struct bcom_task *tsk)108{109 struct bcom_fec_priv *priv = tsk->priv;110 struct bcom_fec_rx_var *var;111 struct bcom_fec_rx_inc *inc;112 113 /* Shutdown the task */114 bcom_disable_task(tsk->tasknum);115 116 /* Reset the microcode */117 var = (struct bcom_fec_rx_var *) bcom_task_var(tsk->tasknum);118 inc = (struct bcom_fec_rx_inc *) bcom_task_inc(tsk->tasknum);119 120 if (bcom_load_image(tsk->tasknum, bcom_fec_rx_task))121 return -1;122 123 var->enable = bcom_eng->regs_base +124 offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);125 var->fifo = (u32) priv->fifo;126 var->bd_base = tsk->bd_pa;127 var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);128 var->bd_start = tsk->bd_pa;129 var->buffer_size = priv->maxbufsize;130 131 inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */132 inc->incr_dst = sizeof(u32); /* task image, but we stick */133 inc->incr_dst_ma= sizeof(u8); /* to the official ones */134 135 /* Reset the BDs */136 tsk->index = 0;137 tsk->outdex = 0;138 139 memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);140 141 /* Configure some stuff */142 bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA);143 bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);144 145 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX);146 147 out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */148 149 return 0;150}151EXPORT_SYMBOL_GPL(bcom_fec_rx_reset);152 153void154bcom_fec_rx_release(struct bcom_task *tsk)155{156 /* Nothing special for the FEC tasks */157 bcom_task_free(tsk);158}159EXPORT_SYMBOL_GPL(bcom_fec_rx_release);160 161 162 163 /* Return 2nd to last DRD */164 /* This is an ugly hack, but at least it's only done165 once at initialization */166static u32 *self_modified_drd(int tasknum)167{168 u32 *desc;169 int num_descs;170 int drd_count;171 int i;172 173 num_descs = bcom_task_num_descs(tasknum);174 desc = bcom_task_desc(tasknum) + num_descs - 1;175 drd_count = 0;176 for (i=0; i<num_descs; i++, desc--)177 if (bcom_desc_is_drd(*desc) && ++drd_count == 3)178 break;179 return desc;180}181 182struct bcom_task *183bcom_fec_tx_init(int queue_len, phys_addr_t fifo)184{185 struct bcom_task *tsk;186 struct bcom_fec_priv *priv;187 188 tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),189 sizeof(struct bcom_fec_priv));190 if (!tsk)191 return NULL;192 193 tsk->flags = BCOM_FLAGS_ENABLE_TASK;194 195 priv = tsk->priv;196 priv->fifo = fifo;197 198 if (bcom_fec_tx_reset(tsk)) {199 bcom_task_free(tsk);200 return NULL;201 }202 203 return tsk;204}205EXPORT_SYMBOL_GPL(bcom_fec_tx_init);206 207int208bcom_fec_tx_reset(struct bcom_task *tsk)209{210 struct bcom_fec_priv *priv = tsk->priv;211 struct bcom_fec_tx_var *var;212 struct bcom_fec_tx_inc *inc;213 214 /* Shutdown the task */215 bcom_disable_task(tsk->tasknum);216 217 /* Reset the microcode */218 var = (struct bcom_fec_tx_var *) bcom_task_var(tsk->tasknum);219 inc = (struct bcom_fec_tx_inc *) bcom_task_inc(tsk->tasknum);220 221 if (bcom_load_image(tsk->tasknum, bcom_fec_tx_task))222 return -1;223 224 var->enable = bcom_eng->regs_base +225 offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);226 var->fifo = (u32) priv->fifo;227 var->DRD = bcom_sram_va2pa(self_modified_drd(tsk->tasknum));228 var->bd_base = tsk->bd_pa;229 var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);230 var->bd_start = tsk->bd_pa;231 232 inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */233 inc->incr_src = sizeof(u32); /* task image, but we stick */234 inc->incr_src_ma= sizeof(u8); /* to the official ones */235 236 /* Reset the BDs */237 tsk->index = 0;238 tsk->outdex = 0;239 240 memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);241 242 /* Configure some stuff */243 bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA);244 bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);245 246 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX);247 248 out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */249 250 return 0;251}252EXPORT_SYMBOL_GPL(bcom_fec_tx_reset);253 254void255bcom_fec_tx_release(struct bcom_task *tsk)256{257 /* Nothing special for the FEC tasks */258 bcom_task_free(tsk);259}260EXPORT_SYMBOL_GPL(bcom_fec_tx_release);261 262 263MODULE_DESCRIPTION("BestComm FEC tasks driver");264MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");265MODULE_LICENSE("GPL v2");266