351 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Driver for MPC52xx processor BestComm General Buffer Descriptor4 *5 * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com>6 * Copyright (C) 2006 AppSpec Computer Technologies Corp.7 * Jeff Gibbons <jeff.gibbons@appspec.com>8 */9 10#include <linux/module.h>11#include <linux/kernel.h>12#include <linux/string.h>13#include <linux/types.h>14#include <asm/errno.h>15#include <asm/io.h>16 17#include <asm/mpc52xx.h>18#include <asm/mpc52xx_psc.h>19 20#include <linux/fsl/bestcomm/bestcomm.h>21#include <linux/fsl/bestcomm/bestcomm_priv.h>22#include <linux/fsl/bestcomm/gen_bd.h>23 24 25/* ======================================================================== */26/* Task image/var/inc */27/* ======================================================================== */28 29/* gen_bd tasks images */30extern u32 bcom_gen_bd_rx_task[];31extern u32 bcom_gen_bd_tx_task[];32 33/* rx task vars that need to be set before enabling the task */34struct bcom_gen_bd_rx_var {35 u32 enable; /* (u16*) address of task's control register */36 u32 fifo; /* (u32*) address of gen_bd's fifo */37 u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */38 u32 bd_last; /* (struct bcom_bd*) end of ring buffer */39 u32 bd_start; /* (struct bcom_bd*) current bd */40 u32 buffer_size; /* size of receive buffer */41};42 43/* rx task incs that need to be set before enabling the task */44struct bcom_gen_bd_rx_inc {45 u16 pad0;46 s16 incr_bytes;47 u16 pad1;48 s16 incr_dst;49};50 51/* tx task vars that need to be set before enabling the task */52struct bcom_gen_bd_tx_var {53 u32 fifo; /* (u32*) address of gen_bd's fifo */54 u32 enable; /* (u16*) address of task's control register */55 u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */56 u32 bd_last; /* (struct bcom_bd*) end of ring buffer */57 u32 bd_start; /* (struct bcom_bd*) current bd */58 u32 buffer_size; /* set by uCode for each packet */59};60 61/* tx task incs that need to be set before enabling the task */62struct bcom_gen_bd_tx_inc {63 u16 pad0;64 s16 incr_bytes;65 u16 pad1;66 s16 incr_src;67 u16 pad2;68 s16 incr_src_ma;69};70 71/* private structure */72struct bcom_gen_bd_priv {73 phys_addr_t fifo;74 int initiator;75 int ipr;76 int maxbufsize;77};78 79 80/* ======================================================================== */81/* Task support code */82/* ======================================================================== */83 84struct bcom_task *85bcom_gen_bd_rx_init(int queue_len, phys_addr_t fifo,86 int initiator, int ipr, int maxbufsize)87{88 struct bcom_task *tsk;89 struct bcom_gen_bd_priv *priv;90 91 tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),92 sizeof(struct bcom_gen_bd_priv));93 if (!tsk)94 return NULL;95 96 tsk->flags = BCOM_FLAGS_NONE;97 98 priv = tsk->priv;99 priv->fifo = fifo;100 priv->initiator = initiator;101 priv->ipr = ipr;102 priv->maxbufsize = maxbufsize;103 104 if (bcom_gen_bd_rx_reset(tsk)) {105 bcom_task_free(tsk);106 return NULL;107 }108 109 return tsk;110}111EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init);112 113int114bcom_gen_bd_rx_reset(struct bcom_task *tsk)115{116 struct bcom_gen_bd_priv *priv = tsk->priv;117 struct bcom_gen_bd_rx_var *var;118 struct bcom_gen_bd_rx_inc *inc;119 120 /* Shutdown the task */121 bcom_disable_task(tsk->tasknum);122 123 /* Reset the microcode */124 var = (struct bcom_gen_bd_rx_var *) bcom_task_var(tsk->tasknum);125 inc = (struct bcom_gen_bd_rx_inc *) bcom_task_inc(tsk->tasknum);126 127 if (bcom_load_image(tsk->tasknum, bcom_gen_bd_rx_task))128 return -1;129 130 var->enable = bcom_eng->regs_base +131 offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);132 var->fifo = (u32) priv->fifo;133 var->bd_base = tsk->bd_pa;134 var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);135 var->bd_start = tsk->bd_pa;136 var->buffer_size = priv->maxbufsize;137 138 inc->incr_bytes = -(s16)sizeof(u32);139 inc->incr_dst = sizeof(u32);140 141 /* Reset the BDs */142 tsk->index = 0;143 tsk->outdex = 0;144 145 memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);146 147 /* Configure some stuff */148 bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_RX_BD_PRAGMA);149 bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);150 151 out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);152 bcom_set_initiator(tsk->tasknum, priv->initiator);153 154 out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */155 156 return 0;157}158EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset);159 160void161bcom_gen_bd_rx_release(struct bcom_task *tsk)162{163 /* Nothing special for the GenBD tasks */164 bcom_task_free(tsk);165}166EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release);167 168 169extern struct bcom_task *170bcom_gen_bd_tx_init(int queue_len, phys_addr_t fifo,171 int initiator, int ipr)172{173 struct bcom_task *tsk;174 struct bcom_gen_bd_priv *priv;175 176 tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_gen_bd),177 sizeof(struct bcom_gen_bd_priv));178 if (!tsk)179 return NULL;180 181 tsk->flags = BCOM_FLAGS_NONE;182 183 priv = tsk->priv;184 priv->fifo = fifo;185 priv->initiator = initiator;186 priv->ipr = ipr;187 188 if (bcom_gen_bd_tx_reset(tsk)) {189 bcom_task_free(tsk);190 return NULL;191 }192 193 return tsk;194}195EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init);196 197int198bcom_gen_bd_tx_reset(struct bcom_task *tsk)199{200 struct bcom_gen_bd_priv *priv = tsk->priv;201 struct bcom_gen_bd_tx_var *var;202 struct bcom_gen_bd_tx_inc *inc;203 204 /* Shutdown the task */205 bcom_disable_task(tsk->tasknum);206 207 /* Reset the microcode */208 var = (struct bcom_gen_bd_tx_var *) bcom_task_var(tsk->tasknum);209 inc = (struct bcom_gen_bd_tx_inc *) bcom_task_inc(tsk->tasknum);210 211 if (bcom_load_image(tsk->tasknum, bcom_gen_bd_tx_task))212 return -1;213 214 var->enable = bcom_eng->regs_base +215 offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]);216 var->fifo = (u32) priv->fifo;217 var->bd_base = tsk->bd_pa;218 var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size);219 var->bd_start = tsk->bd_pa;220 221 inc->incr_bytes = -(s16)sizeof(u32);222 inc->incr_src = sizeof(u32);223 inc->incr_src_ma = sizeof(u8);224 225 /* Reset the BDs */226 tsk->index = 0;227 tsk->outdex = 0;228 229 memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size);230 231 /* Configure some stuff */232 bcom_set_task_pragma(tsk->tasknum, BCOM_GEN_TX_BD_PRAGMA);233 bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum);234 235 out_8(&bcom_eng->regs->ipr[priv->initiator], priv->ipr);236 bcom_set_initiator(tsk->tasknum, priv->initiator);237 238 out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */239 240 return 0;241}242EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset);243 244void245bcom_gen_bd_tx_release(struct bcom_task *tsk)246{247 /* Nothing special for the GenBD tasks */248 bcom_task_free(tsk);249}250EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_release);251 252/* ---------------------------------------------------------------------253 * PSC support code254 */255 256/**257 * bcom_psc_parameters - Bestcomm initialization value table for PSC devices258 *259 * This structure is only used internally. It is a lookup table for PSC260 * specific parameters to bestcomm tasks.261 */262static struct bcom_psc_params {263 int rx_initiator;264 int rx_ipr;265 int tx_initiator;266 int tx_ipr;267} bcom_psc_params[] = {268 [0] = {269 .rx_initiator = BCOM_INITIATOR_PSC1_RX,270 .rx_ipr = BCOM_IPR_PSC1_RX,271 .tx_initiator = BCOM_INITIATOR_PSC1_TX,272 .tx_ipr = BCOM_IPR_PSC1_TX,273 },274 [1] = {275 .rx_initiator = BCOM_INITIATOR_PSC2_RX,276 .rx_ipr = BCOM_IPR_PSC2_RX,277 .tx_initiator = BCOM_INITIATOR_PSC2_TX,278 .tx_ipr = BCOM_IPR_PSC2_TX,279 },280 [2] = {281 .rx_initiator = BCOM_INITIATOR_PSC3_RX,282 .rx_ipr = BCOM_IPR_PSC3_RX,283 .tx_initiator = BCOM_INITIATOR_PSC3_TX,284 .tx_ipr = BCOM_IPR_PSC3_TX,285 },286 [3] = {287 .rx_initiator = BCOM_INITIATOR_PSC4_RX,288 .rx_ipr = BCOM_IPR_PSC4_RX,289 .tx_initiator = BCOM_INITIATOR_PSC4_TX,290 .tx_ipr = BCOM_IPR_PSC4_TX,291 },292 [4] = {293 .rx_initiator = BCOM_INITIATOR_PSC5_RX,294 .rx_ipr = BCOM_IPR_PSC5_RX,295 .tx_initiator = BCOM_INITIATOR_PSC5_TX,296 .tx_ipr = BCOM_IPR_PSC5_TX,297 },298 [5] = {299 .rx_initiator = BCOM_INITIATOR_PSC6_RX,300 .rx_ipr = BCOM_IPR_PSC6_RX,301 .tx_initiator = BCOM_INITIATOR_PSC6_TX,302 .tx_ipr = BCOM_IPR_PSC6_TX,303 },304};305 306/**307 * bcom_psc_gen_bd_rx_init - Allocate a receive bcom_task for a PSC port308 * @psc_num: Number of the PSC to allocate a task for309 * @queue_len: number of buffer descriptors to allocate for the task310 * @fifo: physical address of FIFO register311 * @maxbufsize: Maximum receive data size in bytes.312 *313 * Allocate a bestcomm task structure for receiving data from a PSC.314 */315struct bcom_task * bcom_psc_gen_bd_rx_init(unsigned psc_num, int queue_len,316 phys_addr_t fifo, int maxbufsize)317{318 if (psc_num >= MPC52xx_PSC_MAXNUM)319 return NULL;320 321 return bcom_gen_bd_rx_init(queue_len, fifo,322 bcom_psc_params[psc_num].rx_initiator,323 bcom_psc_params[psc_num].rx_ipr,324 maxbufsize);325}326EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_rx_init);327 328/**329 * bcom_psc_gen_bd_tx_init - Allocate a transmit bcom_task for a PSC port330 * @psc_num: Number of the PSC to allocate a task for331 * @queue_len: number of buffer descriptors to allocate for the task332 * @fifo: physical address of FIFO register333 *334 * Allocate a bestcomm task structure for transmitting data to a PSC.335 */336struct bcom_task *337bcom_psc_gen_bd_tx_init(unsigned psc_num, int queue_len, phys_addr_t fifo)338{339 struct psc;340 return bcom_gen_bd_tx_init(queue_len, fifo,341 bcom_psc_params[psc_num].tx_initiator,342 bcom_psc_params[psc_num].tx_ipr);343}344EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_tx_init);345 346 347MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver");348MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons@appspec.com>");349MODULE_LICENSE("GPL v2");350 351