Path: blob/master/arch/powerpc/sysdev/bestcomm/fec.c
10818 views
/*1* Bestcomm FEC tasks driver2*3*4* Copyright (C) 2006-2007 Sylvain Munaut <[email protected]>5* Copyright (C) 2003-2004 MontaVista, Software, Inc.6* ( by Dale Farnsworth <[email protected]> )7*8* This file is licensed under the terms of the GNU General Public License9* version 2. This program is licensed "as is" without any warranty of any10* kind, whether express or implied.11*/1213#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/types.h>16#include <asm/io.h>1718#include "bestcomm.h"19#include "bestcomm_priv.h"20#include "fec.h"212223/* ======================================================================== */24/* Task image/var/inc */25/* ======================================================================== */2627/* fec tasks images */28extern u32 bcom_fec_rx_task[];29extern u32 bcom_fec_tx_task[];3031/* rx task vars that need to be set before enabling the task */32struct bcom_fec_rx_var {33u32 enable; /* (u16*) address of task's control register */34u32 fifo; /* (u32*) address of fec's fifo */35u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */36u32 bd_last; /* (struct bcom_bd*) end of ring buffer */37u32 bd_start; /* (struct bcom_bd*) current bd */38u32 buffer_size; /* size of receive buffer */39};4041/* rx task incs that need to be set before enabling the task */42struct bcom_fec_rx_inc {43u16 pad0;44s16 incr_bytes;45u16 pad1;46s16 incr_dst;47u16 pad2;48s16 incr_dst_ma;49};5051/* tx task vars that need to be set before enabling the task */52struct bcom_fec_tx_var {53u32 DRD; /* (u32*) address of self-modified DRD */54u32 fifo; /* (u32*) address of fec's fifo */55u32 enable; /* (u16*) address of task's control register */56u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */57u32 bd_last; /* (struct bcom_bd*) end of ring buffer */58u32 bd_start; /* (struct bcom_bd*) current bd */59u32 buffer_size; /* set by uCode for each packet */60};6162/* tx task incs that need to be set before enabling the task */63struct bcom_fec_tx_inc {64u16 pad0;65s16 incr_bytes;66u16 pad1;67s16 incr_src;68u16 pad2;69s16 incr_src_ma;70};7172/* private structure in the task */73struct bcom_fec_priv {74phys_addr_t fifo;75int maxbufsize;76};777879/* ======================================================================== */80/* Task support code */81/* ======================================================================== */8283struct bcom_task *84bcom_fec_rx_init(int queue_len, phys_addr_t fifo, int maxbufsize)85{86struct bcom_task *tsk;87struct bcom_fec_priv *priv;8889tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),90sizeof(struct bcom_fec_priv));91if (!tsk)92return NULL;9394tsk->flags = BCOM_FLAGS_NONE;9596priv = tsk->priv;97priv->fifo = fifo;98priv->maxbufsize = maxbufsize;99100if (bcom_fec_rx_reset(tsk)) {101bcom_task_free(tsk);102return NULL;103}104105return tsk;106}107EXPORT_SYMBOL_GPL(bcom_fec_rx_init);108109int110bcom_fec_rx_reset(struct bcom_task *tsk)111{112struct bcom_fec_priv *priv = tsk->priv;113struct bcom_fec_rx_var *var;114struct bcom_fec_rx_inc *inc;115116/* Shutdown the task */117bcom_disable_task(tsk->tasknum);118119/* Reset the microcode */120var = (struct bcom_fec_rx_var *) bcom_task_var(tsk->tasknum);121inc = (struct bcom_fec_rx_inc *) bcom_task_inc(tsk->tasknum);122123if (bcom_load_image(tsk->tasknum, bcom_fec_rx_task))124return -1;125126var->enable = bcom_eng->regs_base +127offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);128var->fifo = (u32) priv->fifo;129var->bd_base = tsk->bd_pa;130var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);131var->bd_start = tsk->bd_pa;132var->buffer_size = priv->maxbufsize;133134inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */135inc->incr_dst = sizeof(u32); /* task image, but we stick */136inc->incr_dst_ma= sizeof(u8); /* to the official ones */137138/* Reset the BDs */139tsk->index = 0;140tsk->outdex = 0;141142memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);143144/* Configure some stuff */145bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_RX_BD_PRAGMA);146bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);147148out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_RX], BCOM_IPR_FEC_RX);149150out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */151152return 0;153}154EXPORT_SYMBOL_GPL(bcom_fec_rx_reset);155156void157bcom_fec_rx_release(struct bcom_task *tsk)158{159/* Nothing special for the FEC tasks */160bcom_task_free(tsk);161}162EXPORT_SYMBOL_GPL(bcom_fec_rx_release);163164165166/* Return 2nd to last DRD */167/* This is an ugly hack, but at least it's only done168once at initialization */169static u32 *self_modified_drd(int tasknum)170{171u32 *desc;172int num_descs;173int drd_count;174int i;175176num_descs = bcom_task_num_descs(tasknum);177desc = bcom_task_desc(tasknum) + num_descs - 1;178drd_count = 0;179for (i=0; i<num_descs; i++, desc--)180if (bcom_desc_is_drd(*desc) && ++drd_count == 3)181break;182return desc;183}184185struct bcom_task *186bcom_fec_tx_init(int queue_len, phys_addr_t fifo)187{188struct bcom_task *tsk;189struct bcom_fec_priv *priv;190191tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_fec_bd),192sizeof(struct bcom_fec_priv));193if (!tsk)194return NULL;195196tsk->flags = BCOM_FLAGS_ENABLE_TASK;197198priv = tsk->priv;199priv->fifo = fifo;200201if (bcom_fec_tx_reset(tsk)) {202bcom_task_free(tsk);203return NULL;204}205206return tsk;207}208EXPORT_SYMBOL_GPL(bcom_fec_tx_init);209210int211bcom_fec_tx_reset(struct bcom_task *tsk)212{213struct bcom_fec_priv *priv = tsk->priv;214struct bcom_fec_tx_var *var;215struct bcom_fec_tx_inc *inc;216217/* Shutdown the task */218bcom_disable_task(tsk->tasknum);219220/* Reset the microcode */221var = (struct bcom_fec_tx_var *) bcom_task_var(tsk->tasknum);222inc = (struct bcom_fec_tx_inc *) bcom_task_inc(tsk->tasknum);223224if (bcom_load_image(tsk->tasknum, bcom_fec_tx_task))225return -1;226227var->enable = bcom_eng->regs_base +228offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);229var->fifo = (u32) priv->fifo;230var->DRD = bcom_sram_va2pa(self_modified_drd(tsk->tasknum));231var->bd_base = tsk->bd_pa;232var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);233var->bd_start = tsk->bd_pa;234235inc->incr_bytes = -(s16)sizeof(u32); /* These should be in the */236inc->incr_src = sizeof(u32); /* task image, but we stick */237inc->incr_src_ma= sizeof(u8); /* to the official ones */238239/* Reset the BDs */240tsk->index = 0;241tsk->outdex = 0;242243memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);244245/* Configure some stuff */246bcom_set_task_pragma(tsk->tasknum, BCOM_FEC_TX_BD_PRAGMA);247bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);248249out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_FEC_TX], BCOM_IPR_FEC_TX);250251out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */252253return 0;254}255EXPORT_SYMBOL_GPL(bcom_fec_tx_reset);256257void258bcom_fec_tx_release(struct bcom_task *tsk)259{260/* Nothing special for the FEC tasks */261bcom_task_free(tsk);262}263EXPORT_SYMBOL_GPL(bcom_fec_tx_release);264265266MODULE_DESCRIPTION("BestComm FEC tasks driver");267MODULE_AUTHOR("Dale Farnsworth <[email protected]>");268MODULE_LICENSE("GPL v2");269270271272