1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Driver for MPC52xx processor BestComm peripheral controller 4 * 5 * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com> 6 * Copyright (C) 2005 Varma Electronics Oy, 7 * ( by Andrey Volkov <avolkov@varma-el.com> ) 8 * Copyright (C) 2003-2004 MontaVista, Software, Inc. 9 * ( by Dale Farnsworth <dfarnsworth@mvista.com> ) 10 */ 11 12 #include <linux/module.h> 13 #include <linux/kernel.h> 14 #include <linux/slab.h> 15 #include <linux/of.h> 16 #include <linux/of_address.h> 17 #include <linux/of_irq.h> 18 #include <linux/platform_device.h> 19 #include <asm/io.h> 20 #include <asm/irq.h> 21 #include <asm/mpc52xx.h> 22 23 #include <linux/fsl/bestcomm/sram.h> 24 #include <linux/fsl/bestcomm/bestcomm_priv.h> 25 #include "linux/fsl/bestcomm/bestcomm.h" 26 27 #define DRIVER_NAME "bestcomm-core" 28 29 /* MPC5200 device tree match tables */ 30 static const struct of_device_id mpc52xx_sram_ids[] = { 31 { .compatible = "fsl,mpc5200-sram", }, 32 { .compatible = "mpc5200-sram", }, 33 {} 34 }; 35 36 37 struct bcom_engine *bcom_eng = NULL; 38 EXPORT_SYMBOL_GPL(bcom_eng); /* needed for inline functions */ 39 40 /* ======================================================================== */ 41 /* Public and private API */ 42 /* ======================================================================== */ 43 44 /* Private API */ 45 46 struct bcom_task * 47 bcom_task_alloc(int bd_count, int bd_size, int priv_size) 48 { 49 int i, tasknum = -1; 50 struct bcom_task *tsk; 51 52 /* Don't try to do anything if bestcomm init failed */ 53 if (!bcom_eng) 54 return NULL; 55 56 /* Get and reserve a task num */ 57 spin_lock(&bcom_eng->lock); 58 59 for (i=0; i<BCOM_MAX_TASKS; i++) 60 if (!bcom_eng->tdt[i].stop) { /* we use stop as a marker */ 61 bcom_eng->tdt[i].stop = 0xfffffffful; /* dummy addr */ 62 tasknum = i; 63 break; 64 } 65 66 spin_unlock(&bcom_eng->lock); 67 68 if (tasknum < 0) 69 return NULL; 70 71 /* Allocate our structure */ 72 tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL); 73 if (!tsk) 74 goto error; 75 76 tsk->tasknum = tasknum; 77 if (priv_size) 78 tsk->priv = (void*)tsk + sizeof(struct bcom_task); 79 80 /* Get IRQ of that task */ 81 tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum); 82 if (!tsk->irq) 83 goto error; 84 85 /* Init the BDs, if needed */ 86 if (bd_count) { 87 tsk->cookie = kmalloc_array(bd_count, sizeof(void *), 88 GFP_KERNEL); 89 if (!tsk->cookie) 90 goto error; 91 92 tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa); 93 if (!tsk->bd) 94 goto error; 95 memset_io(tsk->bd, 0x00, bd_count * bd_size); 96 97 tsk->num_bd = bd_count; 98 tsk->bd_size = bd_size; 99 } 100 101 return tsk; 102 103 error: 104 if (tsk) { 105 if (tsk->irq) 106 irq_dispose_mapping(tsk->irq); 107 bcom_sram_free(tsk->bd); 108 kfree(tsk->cookie); 109 kfree(tsk); 110 } 111 112 bcom_eng->tdt[tasknum].stop = 0; 113 114 return NULL; 115 } 116 EXPORT_SYMBOL_GPL(bcom_task_alloc); 117 118 void 119 bcom_task_free(struct bcom_task *tsk) 120 { 121 /* Stop the task */ 122 bcom_disable_task(tsk->tasknum); 123 124 /* Clear TDT */ 125 bcom_eng->tdt[tsk->tasknum].start = 0; 126 bcom_eng->tdt[tsk->tasknum].stop = 0; 127 128 /* Free everything */ 129 irq_dispose_mapping(tsk->irq); 130 bcom_sram_free(tsk->bd); 131 kfree(tsk->cookie); 132 kfree(tsk); 133 } 134 EXPORT_SYMBOL_GPL(bcom_task_free); 135 136 int 137 bcom_load_image(int task, u32 *task_image) 138 { 139 struct bcom_task_header *hdr = (struct bcom_task_header *)task_image; 140 struct bcom_tdt *tdt; 141 u32 *desc, *var, *inc; 142 u32 *desc_src, *var_src, *inc_src; 143 144 /* Safety checks */ 145 if (hdr->magic != BCOM_TASK_MAGIC) { 146 printk(KERN_ERR DRIVER_NAME 147 ": Trying to load invalid microcode\n"); 148 return -EINVAL; 149 } 150 151 if ((task < 0) || (task >= BCOM_MAX_TASKS)) { 152 printk(KERN_ERR DRIVER_NAME 153 ": Trying to load invalid task %d\n", task); 154 return -EINVAL; 155 } 156 157 /* Initial load or reload */ 158 tdt = &bcom_eng->tdt[task]; 159 160 if (tdt->start) { 161 desc = bcom_task_desc(task); 162 if (hdr->desc_size != bcom_task_num_descs(task)) { 163 printk(KERN_ERR DRIVER_NAME 164 ": Trying to reload wrong task image " 165 "(%d size %d/%d)!\n", 166 task, 167 hdr->desc_size, 168 bcom_task_num_descs(task)); 169 return -EINVAL; 170 } 171 } else { 172 phys_addr_t start_pa; 173 174 desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa); 175 if (!desc) 176 return -ENOMEM; 177 178 tdt->start = start_pa; 179 tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32)); 180 } 181 182 var = bcom_task_var(task); 183 inc = bcom_task_inc(task); 184 185 /* Clear & copy */ 186 memset_io(var, 0x00, BCOM_VAR_SIZE); 187 memset_io(inc, 0x00, BCOM_INC_SIZE); 188 189 desc_src = (u32 *)(hdr + 1); 190 var_src = desc_src + hdr->desc_size; 191 inc_src = var_src + hdr->var_size; 192 193 memcpy_toio(desc, desc_src, hdr->desc_size * sizeof(u32)); 194 memcpy_toio(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32)); 195 memcpy_toio(inc, inc_src, hdr->inc_size * sizeof(u32)); 196 197 return 0; 198 } 199 EXPORT_SYMBOL_GPL(bcom_load_image); 200 201 void 202 bcom_set_initiator(int task, int initiator) 203 { 204 int i; 205 int num_descs; 206 u32 *desc; 207 int next_drd_has_initiator; 208 209 bcom_set_tcr_initiator(task, initiator); 210 211 /* Just setting tcr is apparently not enough due to some problem */ 212 /* with it. So we just go thru all the microcode and replace in */ 213 /* the DRD directly */ 214 215 desc = bcom_task_desc(task); 216 next_drd_has_initiator = 1; 217 num_descs = bcom_task_num_descs(task); 218 219 for (i=0; i<num_descs; i++, desc++) { 220 if (!bcom_desc_is_drd(*desc)) 221 continue; 222 if (next_drd_has_initiator) 223 if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS) 224 bcom_set_desc_initiator(desc, initiator); 225 next_drd_has_initiator = !bcom_drd_is_extended(*desc); 226 } 227 } 228 EXPORT_SYMBOL_GPL(bcom_set_initiator); 229 230 231 /* Public API */ 232 233 void 234 bcom_enable(struct bcom_task *tsk) 235 { 236 bcom_enable_task(tsk->tasknum); 237 } 238 EXPORT_SYMBOL_GPL(bcom_enable); 239 240 void 241 bcom_disable(struct bcom_task *tsk) 242 { 243 bcom_disable_task(tsk->tasknum); 244 } 245 EXPORT_SYMBOL_GPL(bcom_disable); 246 247 248 /* ======================================================================== */ 249 /* Engine init/cleanup */ 250 /* ======================================================================== */ 251 252 /* Function Descriptor table */ 253 /* this will need to be updated if Freescale changes their task code FDT */ 254 static u32 fdt_ops[] = { 255 0xa0045670, /* FDT[48] - load_acc() */ 256 0x80045670, /* FDT[49] - unload_acc() */ 257 0x21800000, /* FDT[50] - and() */ 258 0x21e00000, /* FDT[51] - or() */ 259 0x21500000, /* FDT[52] - xor() */ 260 0x21400000, /* FDT[53] - andn() */ 261 0x21500000, /* FDT[54] - not() */ 262 0x20400000, /* FDT[55] - add() */ 263 0x20500000, /* FDT[56] - sub() */ 264 0x20800000, /* FDT[57] - lsh() */ 265 0x20a00000, /* FDT[58] - rsh() */ 266 0xc0170000, /* FDT[59] - crc8() */ 267 0xc0145670, /* FDT[60] - crc16() */ 268 0xc0345670, /* FDT[61] - crc32() */ 269 0xa0076540, /* FDT[62] - endian32() */ 270 0xa0000760, /* FDT[63] - endian16() */ 271 }; 272 273 274 static int bcom_engine_init(void) 275 { 276 int task; 277 phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; 278 unsigned int tdt_size, ctx_size, var_size, fdt_size; 279 280 /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ 281 tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); 282 ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE; 283 var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE); 284 fdt_size = BCOM_FDT_SIZE; 285 286 bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa); 287 bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa); 288 bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa); 289 bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa); 290 291 if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) { 292 printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n"); 293 294 bcom_sram_free(bcom_eng->tdt); 295 bcom_sram_free(bcom_eng->ctx); 296 bcom_sram_free(bcom_eng->var); 297 bcom_sram_free(bcom_eng->fdt); 298 299 return -ENOMEM; 300 } 301 302 memset_io(bcom_eng->tdt, 0x00, tdt_size); 303 memset_io(bcom_eng->ctx, 0x00, ctx_size); 304 memset_io(bcom_eng->var, 0x00, var_size); 305 memset_io(bcom_eng->fdt, 0x00, fdt_size); 306 307 /* Copy the FDT for the EU#3 */ 308 memcpy_toio(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops)); 309 310 /* Initialize Task base structure */ 311 for (task=0; task<BCOM_MAX_TASKS; task++) 312 { 313 out_be16(&bcom_eng->regs->tcr[task], 0); 314 out_8(&bcom_eng->regs->ipr[task], 0); 315 316 bcom_eng->tdt[task].context = ctx_pa; 317 bcom_eng->tdt[task].var = var_pa; 318 bcom_eng->tdt[task].fdt = fdt_pa; 319 320 var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE; 321 ctx_pa += BCOM_CTX_SIZE; 322 } 323 324 out_be32(&bcom_eng->regs->taskBar, tdt_pa); 325 326 /* Init 'always' initiator */ 327 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); 328 329 /* Disable COMM Bus Prefetch on the original 5200; it's broken */ 330 if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR) 331 bcom_disable_prefetch(); 332 333 /* Init lock */ 334 spin_lock_init(&bcom_eng->lock); 335 336 return 0; 337 } 338 339 static void 340 bcom_engine_cleanup(void) 341 { 342 int task; 343 344 /* Stop all tasks */ 345 for (task=0; task<BCOM_MAX_TASKS; task++) 346 { 347 out_be16(&bcom_eng->regs->tcr[task], 0); 348 out_8(&bcom_eng->regs->ipr[task], 0); 349 } 350 351 out_be32(&bcom_eng->regs->taskBar, 0ul); 352 353 /* Release the SRAM zones */ 354 bcom_sram_free(bcom_eng->tdt); 355 bcom_sram_free(bcom_eng->ctx); 356 bcom_sram_free(bcom_eng->var); 357 bcom_sram_free(bcom_eng->fdt); 358 } 359 360 361 /* ======================================================================== */ 362 /* OF platform driver */ 363 /* ======================================================================== */ 364 365 static int mpc52xx_bcom_probe(struct platform_device *op) 366 { 367 struct device_node *ofn_sram; 368 struct resource res_bcom; 369 370 int rv; 371 372 /* Inform user we're ok so far */ 373 printk(KERN_INFO "DMA: MPC52xx BestComm driver\n"); 374 375 /* Get the bestcomm node */ 376 of_node_get(op->dev.of_node); 377 378 /* Prepare SRAM */ 379 ofn_sram = of_find_matching_node(NULL, mpc52xx_sram_ids); 380 if (!ofn_sram) { 381 printk(KERN_ERR DRIVER_NAME ": " 382 "No SRAM found in device tree\n"); 383 rv = -ENODEV; 384 goto error_ofput; 385 } 386 rv = bcom_sram_init(ofn_sram, DRIVER_NAME); 387 of_node_put(ofn_sram); 388 389 if (rv) { 390 printk(KERN_ERR DRIVER_NAME ": " 391 "Error in SRAM init\n"); 392 goto error_ofput; 393 } 394 395 /* Get a clean struct */ 396 bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL); 397 if (!bcom_eng) { 398 rv = -ENOMEM; 399 goto error_sramclean; 400 } 401 402 /* Save the node */ 403 bcom_eng->ofnode = op->dev.of_node; 404 405 /* Get, reserve & map io */ 406 if (of_address_to_resource(op->dev.of_node, 0, &res_bcom)) { 407 printk(KERN_ERR DRIVER_NAME ": " 408 "Can't get resource\n"); 409 rv = -EINVAL; 410 goto error_sramclean; 411 } 412 413 if (!request_mem_region(res_bcom.start, resource_size(&res_bcom), 414 DRIVER_NAME)) { 415 printk(KERN_ERR DRIVER_NAME ": " 416 "Can't request registers region\n"); 417 rv = -EBUSY; 418 goto error_sramclean; 419 } 420 421 bcom_eng->regs_base = res_bcom.start; 422 bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma)); 423 if (!bcom_eng->regs) { 424 printk(KERN_ERR DRIVER_NAME ": " 425 "Can't map registers\n"); 426 rv = -ENOMEM; 427 goto error_release; 428 } 429 430 /* Now, do the real init */ 431 rv = bcom_engine_init(); 432 if (rv) 433 goto error_unmap; 434 435 /* Done ! */ 436 printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n", 437 (long)bcom_eng->regs_base); 438 439 return 0; 440 441 /* Error path */ 442 error_unmap: 443 iounmap(bcom_eng->regs); 444 error_release: 445 release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma)); 446 error_sramclean: 447 kfree(bcom_eng); 448 bcom_sram_cleanup(); 449 error_ofput: 450 of_node_put(op->dev.of_node); 451 452 printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n"); 453 454 return rv; 455 } 456 457 458 static void mpc52xx_bcom_remove(struct platform_device *op) 459 { 460 /* Clean up the engine */ 461 bcom_engine_cleanup(); 462 463 /* Cleanup SRAM */ 464 bcom_sram_cleanup(); 465 466 /* Release regs */ 467 iounmap(bcom_eng->regs); 468 release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma)); 469 470 /* Release the node */ 471 of_node_put(bcom_eng->ofnode); 472 473 /* Release memory */ 474 kfree(bcom_eng); 475 bcom_eng = NULL; 476 } 477 478 static const struct of_device_id mpc52xx_bcom_of_match[] = { 479 { .compatible = "fsl,mpc5200-bestcomm", }, 480 { .compatible = "mpc5200-bestcomm", }, 481 {}, 482 }; 483 484 MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match); 485 486 487 static struct platform_driver mpc52xx_bcom_of_platform_driver = { 488 .probe = mpc52xx_bcom_probe, 489 .remove_new = mpc52xx_bcom_remove, 490 .driver = { 491 .name = DRIVER_NAME, 492 .of_match_table = mpc52xx_bcom_of_match, 493 }, 494 }; 495 496 497 /* ======================================================================== */ 498 /* Module */ 499 /* ======================================================================== */ 500 501 static int __init 502 mpc52xx_bcom_init(void) 503 { 504 return platform_driver_register(&mpc52xx_bcom_of_platform_driver); 505 } 506 507 static void __exit 508 mpc52xx_bcom_exit(void) 509 { 510 platform_driver_unregister(&mpc52xx_bcom_of_platform_driver); 511 } 512 513 /* If we're not a module, we must make sure everything is setup before */ 514 /* anyone tries to use us ... that's why we use subsys_initcall instead */ 515 /* of module_init. */ 516 subsys_initcall(mpc52xx_bcom_init); 517 module_exit(mpc52xx_bcom_exit); 518 519 MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA"); 520 MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>"); 521 MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>"); 522 MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>"); 523 MODULE_LICENSE("GPL v2"); 524