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