1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Driver for MPC52xx processor BestComm General Buffer Descriptor 4 * 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 */ 30 extern u32 bcom_gen_bd_rx_task[]; 31 extern u32 bcom_gen_bd_tx_task[]; 32 33 /* rx task vars that need to be set before enabling the task */ 34 struct 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 */ 44 struct 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 */ 52 struct 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 */ 62 struct 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 */ 72 struct 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 84 struct bcom_task * 85 bcom_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 } 111 EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_init); 112 113 int 114 bcom_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 } 158 EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_reset); 159 160 void 161 bcom_gen_bd_rx_release(struct bcom_task *tsk) 162 { 163 /* Nothing special for the GenBD tasks */ 164 bcom_task_free(tsk); 165 } 166 EXPORT_SYMBOL_GPL(bcom_gen_bd_rx_release); 167 168 169 extern struct bcom_task * 170 bcom_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 } 195 EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_init); 196 197 int 198 bcom_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 } 242 EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_reset); 243 244 void 245 bcom_gen_bd_tx_release(struct bcom_task *tsk) 246 { 247 /* Nothing special for the GenBD tasks */ 248 bcom_task_free(tsk); 249 } 250 EXPORT_SYMBOL_GPL(bcom_gen_bd_tx_release); 251 252 /* --------------------------------------------------------------------- 253 * PSC support code 254 */ 255 256 /** 257 * bcom_psc_parameters - Bestcomm initialization value table for PSC devices 258 * 259 * This structure is only used internally. It is a lookup table for PSC 260 * specific parameters to bestcomm tasks. 261 */ 262 static 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 port 308 * @psc_num: Number of the PSC to allocate a task for 309 * @queue_len: number of buffer descriptors to allocate for the task 310 * @fifo: physical address of FIFO register 311 * @maxbufsize: Maximum receive data size in bytes. 312 * 313 * Allocate a bestcomm task structure for receiving data from a PSC. 314 */ 315 struct 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 } 326 EXPORT_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 port 330 * @psc_num: Number of the PSC to allocate a task for 331 * @queue_len: number of buffer descriptors to allocate for the task 332 * @fifo: physical address of FIFO register 333 * 334 * Allocate a bestcomm task structure for transmitting data to a PSC. 335 */ 336 struct bcom_task * 337 bcom_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 } 344 EXPORT_SYMBOL_GPL(bcom_psc_gen_bd_tx_init); 345 346 347 MODULE_DESCRIPTION("BestComm General Buffer Descriptor tasks driver"); 348 MODULE_AUTHOR("Jeff Gibbons <jeff.gibbons@appspec.com>"); 349 MODULE_LICENSE("GPL v2"); 350 351