Path: blob/master/arch/powerpc/sysdev/bestcomm/gen_bd.c
10818 views
/*1* Driver for MPC52xx processor BestComm General Buffer Descriptor2*3* Copyright (C) 2007 Sylvain Munaut <[email protected]>4* Copyright (C) 2006 AppSpec Computer Technologies Corp.5* Jeff Gibbons <[email protected]>6*7* This program is free software; you can redistribute it and/or modify it8* under the terms of the GNU General Public License version 2 as published9* by the Free Software Foundation.10*11*/1213#include <linux/module.h>14#include <linux/kernel.h>15#include <linux/string.h>16#include <linux/types.h>17#include <asm/errno.h>18#include <asm/io.h>1920#include <asm/mpc52xx.h>21#include <asm/mpc52xx_psc.h>2223#include "bestcomm.h"24#include "bestcomm_priv.h"25#include "gen_bd.h"262728/* ======================================================================== */29/* Task image/var/inc */30/* ======================================================================== */3132/* gen_bd tasks images */33extern u32 bcom_gen_bd_rx_task[];34extern u32 bcom_gen_bd_tx_task[];3536/* rx task vars that need to be set before enabling the task */37struct bcom_gen_bd_rx_var {38u32 enable; /* (u16*) address of task's control register */39u32 fifo; /* (u32*) address of gen_bd's fifo */40u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */41u32 bd_last; /* (struct bcom_bd*) end of ring buffer */42u32 bd_start; /* (struct bcom_bd*) current bd */43u32 buffer_size; /* size of receive buffer */44};4546/* rx task incs that need to be set before enabling the task */47struct bcom_gen_bd_rx_inc {48u16 pad0;49s16 incr_bytes;50u16 pad1;51s16 incr_dst;52};5354/* tx task vars that need to be set before enabling the task */55struct bcom_gen_bd_tx_var {56u32 fifo; /* (u32*) address of gen_bd's fifo */57u32 enable; /* (u16*) address of task's control register */58u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */59u32 bd_last; /* (struct bcom_bd*) end of ring buffer */60u32 bd_start; /* (struct bcom_bd*) current bd */61u32 buffer_size; /* set by uCode for each packet */62};6364/* tx task incs that need to be set before enabling the task */65struct bcom_gen_bd_tx_inc {66u16 pad0;67s16 incr_bytes;68u16 pad1;69s16 incr_src;70u16 pad2;71s16 incr_src_ma;72};7374/* private structure */75struct bcom_gen_bd_priv {76phys_addr_t fifo;77int initiator;78int ipr;79int maxbufsize;80};818283/* ======================================================================== */84/* Task support code */85/* ======================================================================== */8687struct bcom_task *88bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,89int initiator, int ipr, int maxbufsize)90{91struct bcom_task *tsk;92struct bcom_gen_bd_priv *priv;9394tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),95sizeof(struct bcom_gen_bd_priv));96if (!tsk)97return NULL;9899tsk->flags = BCOM_FLAGS_NONE;100101priv = tsk->priv;102priv->fifo = fifo;103priv->initiator = initiator;104priv->ipr = ipr;105priv->maxbufsize = maxbufsize;106107if (bcom_gen_bd_rx_reset(tsk)) {108bcom_task_free(tsk);109return NULL;110}111112return tsk;113}114EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init);115116int117bcom_gen_bd_rx_reset(struct bcom_task *tsk)118{119struct bcom_gen_bd_priv *priv = tsk->priv;120struct bcom_gen_bd_rx_var *var;121struct bcom_gen_bd_rx_inc *inc;122123/* Shutdown the task */124bcom_disable_task(tsk->tasknum);125126/* Reset the microcode */127var = (struct bcom_gen_bd_rx_var *) bcom_task_var(tsk->tasknum);128inc = (struct bcom_gen_bd_rx_inc *) bcom_task_inc(tsk->tasknum);129130if (bcom_load_image(tsk->tasknum, bcom_gen_bd_rx_task))131return -1;132133var->enable = bcom_eng->regs_base +134offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);135var->fifo = (u32) priv->fifo;136var->bd_base = tsk->bd_pa;137var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);138var->bd_start = tsk->bd_pa;139var->buffer_size = priv->maxbufsize;140141inc->incr_bytes = -(s16)sizeof(u32);142inc->incr_dst = sizeof(u32);143144/* Reset the BDs */145tsk->index = 0;146tsk->outdex = 0;147148memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);149150/* Configure some stuff */151bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_RX_BD_PRAGMA);152bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);153154out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);155bcom_set_initiator(tsk->tasknum, priv->initiator);156157out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */158159return 0;160}161EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset);162163void164bcom_gen_bd_rx_release(struct bcom_task *tsk)165{166/* Nothing special for the GenBD tasks */167bcom_task_free(tsk);168}169EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release);170171172extern struct bcom_task *173bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,174int initiator, int ipr)175{176struct bcom_task *tsk;177struct bcom_gen_bd_priv *priv;178179tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),180sizeof(struct bcom_gen_bd_priv));181if (!tsk)182return NULL;183184tsk->flags = BCOM_FLAGS_NONE;185186priv = tsk->priv;187priv->fifo = fifo;188priv->initiator = initiator;189priv->ipr = ipr;190191if (bcom_gen_bd_tx_reset(tsk)) {192bcom_task_free(tsk);193return NULL;194}195196return tsk;197}198EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init);199200int201bcom_gen_bd_tx_reset(struct bcom_task *tsk)202{203struct bcom_gen_bd_priv *priv = tsk->priv;204struct bcom_gen_bd_tx_var *var;205struct bcom_gen_bd_tx_inc *inc;206207/* Shutdown the task */208bcom_disable_task(tsk->tasknum);209210/* Reset the microcode */211var = (struct bcom_gen_bd_tx_var *) bcom_task_var(tsk->tasknum);212inc = (struct bcom_gen_bd_tx_inc *) bcom_task_inc(tsk->tasknum);213214if (bcom_load_image(tsk->tasknum, bcom_gen_bd_tx_task))215return -1;216217var->enable = bcom_eng->regs_base +218offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);219var->fifo = (u32) priv->fifo;220var->bd_base = tsk->bd_pa;221var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);222var->bd_start = tsk->bd_pa;223224inc->incr_bytes = -(s16)sizeof(u32);225inc->incr_src = sizeof(u32);226inc->incr_src_ma = sizeof(u8);227228/* Reset the BDs */229tsk->index = 0;230tsk->outdex = 0;231232memset(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);233234/* Configure some stuff */235bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_TX_BD_PRAGMA);236bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);237238out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);239bcom_set_initiator(tsk->tasknum, priv->initiator);240241out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */242243return 0;244}245EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset);246247void248bcom_gen_bd_tx_release(struct bcom_task *tsk)249{250/* Nothing special for the GenBD tasks */251bcom_task_free(tsk);252}253EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_release);254255/* ---------------------------------------------------------------------256* PSC support code257*/258259/**260* bcom_psc_parameters - Bestcomm initialization value table for PSC devices261*262* This structure is only used internally. It is a lookup table for PSC263* specific parameters to bestcomm tasks.264*/265static struct bcom_psc_params {266int rx_initiator;267int rx_ipr;268int tx_initiator;269int tx_ipr;270} bcom_psc_params[] = {271[0] = {272.rx_initiator = BCOM_INITIATOR_PSC1_RX,273.rx_ipr = BCOM_IPR_PSC1_RX,274.tx_initiator = BCOM_INITIATOR_PSC1_TX,275.tx_ipr = BCOM_IPR_PSC1_TX,276},277[1] = {278.rx_initiator = BCOM_INITIATOR_PSC2_RX,279.rx_ipr = BCOM_IPR_PSC2_RX,280.tx_initiator = BCOM_INITIATOR_PSC2_TX,281.tx_ipr = BCOM_IPR_PSC2_TX,282},283[2] = {284.rx_initiator = BCOM_INITIATOR_PSC3_RX,285.rx_ipr = BCOM_IPR_PSC3_RX,286.tx_initiator = BCOM_INITIATOR_PSC3_TX,287.tx_ipr = BCOM_IPR_PSC3_TX,288},289[3] = {290.rx_initiator = BCOM_INITIATOR_PSC4_RX,291.rx_ipr = BCOM_IPR_PSC4_RX,292.tx_initiator = BCOM_INITIATOR_PSC4_TX,293.tx_ipr = BCOM_IPR_PSC4_TX,294},295[4] = {296.rx_initiator = BCOM_INITIATOR_PSC5_RX,297.rx_ipr = BCOM_IPR_PSC5_RX,298.tx_initiator = BCOM_INITIATOR_PSC5_TX,299.tx_ipr = BCOM_IPR_PSC5_TX,300},301[5] = {302.rx_initiator = BCOM_INITIATOR_PSC6_RX,303.rx_ipr = BCOM_IPR_PSC6_RX,304.tx_initiator = BCOM_INITIATOR_PSC6_TX,305.tx_ipr = BCOM_IPR_PSC6_TX,306},307};308309/**310* bcom_psc_gen_bd_rx_init - Allocate a receive bcom_task for a PSC port311* @psc_num: Number of the PSC to allocate a task for312* @queue_len: number of buffer descriptors to allocate for the task313* @fifo: physical address of FIFO register314* @maxbufsize: Maximum receive data size in bytes.315*316* Allocate a bestcomm task structure for receiving data from a PSC.317*/318struct bcom_task * bcom_psc_gen_bd_rx_init(unsigned psc_num, int queue_len,319phys_addr_t fifo, int maxbufsize)320{321if (psc_num >= MPC52xx_PSC_MAXNUM)322return NULL;323324return bcom_gen_bd_rx_init(queue_len, fifo,325bcom_psc_params[psc_num].rx_initiator,326bcom_psc_params[psc_num].rx_ipr,327maxbufsize);328}329EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_rx_init);330331/**332* bcom_psc_gen_bd_tx_init - Allocate a transmit bcom_task for a PSC port333* @psc_num: Number of the PSC to allocate a task for334* @queue_len: number of buffer descriptors to allocate for the task335* @fifo: physical address of FIFO register336*337* Allocate a bestcomm task structure for transmitting data to a PSC.338*/339struct bcom_task *340bcom_psc_gen_bd_tx_init(unsigned psc_num, int queue_len, phys_addr_t fifo)341{342struct psc;343return bcom_gen_bd_tx_init(queue_len, fifo,344bcom_psc_params[psc_num].tx_initiator,345bcom_psc_params[psc_num].tx_ipr);346}347EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_tx_init);348349350MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver");351MODULE_AUTHOR("Jeff Gibbons <[email protected]>");352MODULE_LICENSE("GPL v2");353354355356