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 <linux/fsl/bestcomm/bestcomm.h> 25 #include <linux/fsl/bestcomm/bestcomm_priv.h> 26 #include <linux/fsl/bestcomm/gen_bd.h> 27 28 29 /* ======================================================================== */ 30 /* Task image/var/inc */ 31 /* ======================================================================== */ 32 33 /* gen_bd tasks images */ 34 extern u32 bcom_gen_bd_rx_task[]; 35 extern u32 bcom_gen_bd_tx_task[]; 36 37 /* rx task vars that need to be set before enabling the task */ 38 struct 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 */ 48 struct 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 */ 56 struct 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 */ 66 struct 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 */ 76 struct 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 88 struct bcom_task * 89 bcom_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 } 115 EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init); 116 117 int 118 bcom_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 } 162 EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset); 163 164 void 165 bcom_gen_bd_rx_release(struct bcom_task *tsk) 166 { 167 /* Nothing special for the GenBD tasks */ 168 bcom_task_free(tsk); 169 } 170 EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release); 171 172 173 extern struct bcom_task * 174 bcom_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 } 199 EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init); 200 201 int 202 bcom_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 } 246 EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset); 247 248 void 249 bcom_gen_bd_tx_release(struct bcom_task *tsk) 250 { 251 /* Nothing special for the GenBD tasks */ 252 bcom_task_free(tsk); 253 } 254 EXPORT_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 */ 266 static 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 */ 319 struct 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 } 330 EXPORT_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 */ 340 struct bcom_task * 341 bcom_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 } 348 EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_tx_init); 349 350 351 MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver"); 352 MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons@appspec.com>"); 353 MODULE_LICENSE("GPL v2"); 354 355