Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[POWERPC] bestcomm: core bestcomm support for Freescale MPC5200

This patch adds support for the core of the BestComm API
for the Freescale MPC5200(b). The BestComm engine is a
microcode-controlled / tasks-based DMA used by several
of the onchip devices.

Setting up the tasks / memory allocation and all common
low level functions are handled by this patch.
The specifics details of each tasks and their microcode
are split-out in separate patches.

This is not the official API, but a much cleaner one.
(hopefully)

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

authored by

Sylvain Munaut and committed by
Grant Likely
2f9ea1bd 07e6e931

+1312
+2
arch/powerpc/platforms/Kconfig
··· 315 315 config CPM 316 316 bool 317 317 318 + source "arch/powerpc/sysdev/bestcomm/Kconfig" 319 + 318 320 endmenu
+1
arch/powerpc/sysdev/Makefile
··· 14 14 obj-$(CONFIG_FSL_PCI) += fsl_pci.o 15 15 obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o 16 16 obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ 17 + obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ 17 18 mv64x60-$(CONFIG_PCI) += mv64x60_pci.o 18 19 obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o \ 19 20 mv64x60_udbg.o
+18
arch/powerpc/sysdev/bestcomm/Kconfig
··· 1 + # 2 + # Kconfig options for Bestcomm 3 + # 4 + 5 + config PPC_BESTCOMM 6 + tristate "Bestcomm DMA engine support" 7 + depends on PPC_MPC52xx 8 + default n 9 + select PPC_LIB_RHEAP 10 + help 11 + BestComm is the name of the communication coprocessor found 12 + on the Freescale MPC5200 family of processor. It's usage is 13 + optionnal for some drivers (like ATA), but required for 14 + others (like FEC). 15 + 16 + If you want to use drivers that require DMA operations, 17 + answer Y or M. Otherwise say N. 18 +
+8
arch/powerpc/sysdev/bestcomm/Makefile
··· 1 + # 2 + # Makefile for BestComm & co 3 + # 4 + 5 + bestcomm-core-objs := bestcomm.o sram.o 6 + 7 + obj-$(CONFIG_PPC_BESTCOMM) += bestcomm-core.o 8 +
+528
arch/powerpc/sysdev/bestcomm/bestcomm.c
··· 1 + /* 2 + * Driver for MPC52xx processor BestComm peripheral controller 3 + * 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 + * This file is licensed under the terms of the GNU General Public License 12 + * version 2. This program is licensed "as is" without any warranty of any 13 + * kind, whether express or implied. 14 + */ 15 + 16 + #include <linux/module.h> 17 + #include <linux/kernel.h> 18 + #include <linux/slab.h> 19 + #include <linux/of.h> 20 + #include <linux/of_device.h> 21 + #include <linux/of_platform.h> 22 + #include <asm/io.h> 23 + #include <asm/irq.h> 24 + #include <asm/mpc52xx.h> 25 + 26 + #include "sram.h" 27 + #include "bestcomm_priv.h" 28 + #include "bestcomm.h" 29 + 30 + #define DRIVER_NAME "bestcomm-core" 31 + 32 + 33 + struct bcom_engine *bcom_eng = NULL; 34 + EXPORT_SYMBOL_GPL(bcom_eng); /* needed for inline functions */ 35 + 36 + 37 + /* ======================================================================== */ 38 + /* Public and private API */ 39 + /* ======================================================================== */ 40 + 41 + /* Private API */ 42 + 43 + struct bcom_task * 44 + bcom_task_alloc(int bd_count, int bd_size, int priv_size) 45 + { 46 + int i, tasknum = -1; 47 + struct bcom_task *tsk; 48 + 49 + /* Get and reserve a task num */ 50 + spin_lock(&bcom_eng->lock); 51 + 52 + for (i=0; i<BCOM_MAX_TASKS; i++) 53 + if (!bcom_eng->tdt[i].stop) { /* we use stop as a marker */ 54 + bcom_eng->tdt[i].stop = 0xfffffffful; /* dummy addr */ 55 + tasknum = i; 56 + break; 57 + } 58 + 59 + spin_unlock(&bcom_eng->lock); 60 + 61 + if (tasknum < 0) 62 + return NULL; 63 + 64 + /* Allocate our structure */ 65 + tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL); 66 + if (!tsk) 67 + goto error; 68 + 69 + tsk->tasknum = tasknum; 70 + if (priv_size) 71 + tsk->priv = (void*)tsk + sizeof(struct bcom_task); 72 + 73 + /* Get IRQ of that task */ 74 + tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum); 75 + if (tsk->irq == NO_IRQ) 76 + goto error; 77 + 78 + /* Init the BDs, if needed */ 79 + if (bd_count) { 80 + tsk->cookie = kmalloc(sizeof(void*) * bd_count, GFP_KERNEL); 81 + if (!tsk->cookie) 82 + goto error; 83 + 84 + tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa); 85 + if (!tsk->bd) 86 + goto error; 87 + memset(tsk->bd, 0x00, bd_count * bd_size); 88 + 89 + tsk->num_bd = bd_count; 90 + tsk->bd_size = bd_size; 91 + } 92 + 93 + return tsk; 94 + 95 + error: 96 + if (tsk) { 97 + if (tsk->irq != NO_IRQ) 98 + irq_dispose_mapping(tsk->irq); 99 + bcom_sram_free(tsk->bd); 100 + kfree(tsk->cookie); 101 + kfree(tsk); 102 + } 103 + 104 + bcom_eng->tdt[tasknum].stop = 0; 105 + 106 + return NULL; 107 + } 108 + EXPORT_SYMBOL_GPL(bcom_task_alloc); 109 + 110 + void 111 + bcom_task_free(struct bcom_task *tsk) 112 + { 113 + /* Stop the task */ 114 + bcom_disable_task(tsk->tasknum); 115 + 116 + /* Clear TDT */ 117 + bcom_eng->tdt[tsk->tasknum].start = 0; 118 + bcom_eng->tdt[tsk->tasknum].stop = 0; 119 + 120 + /* Free everything */ 121 + irq_dispose_mapping(tsk->irq); 122 + bcom_sram_free(tsk->bd); 123 + kfree(tsk->cookie); 124 + kfree(tsk); 125 + } 126 + EXPORT_SYMBOL_GPL(bcom_task_free); 127 + 128 + int 129 + bcom_load_image(int task, u32 *task_image) 130 + { 131 + struct bcom_task_header *hdr = (struct bcom_task_header *)task_image; 132 + struct bcom_tdt *tdt; 133 + u32 *desc, *var, *inc; 134 + u32 *desc_src, *var_src, *inc_src; 135 + 136 + /* Safety checks */ 137 + if (hdr->magic != BCOM_TASK_MAGIC) { 138 + printk(KERN_ERR DRIVER_NAME 139 + ": Trying to load invalid microcode\n"); 140 + return -EINVAL; 141 + } 142 + 143 + if ((task < 0) || (task >= BCOM_MAX_TASKS)) { 144 + printk(KERN_ERR DRIVER_NAME 145 + ": Trying to load invalid task %d\n", task); 146 + return -EINVAL; 147 + } 148 + 149 + /* Initial load or reload */ 150 + tdt = &bcom_eng->tdt[task]; 151 + 152 + if (tdt->start) { 153 + desc = bcom_task_desc(task); 154 + if (hdr->desc_size != bcom_task_num_descs(task)) { 155 + printk(KERN_ERR DRIVER_NAME 156 + ": Trying to reload wrong task image " 157 + "(%d size %d/%d)!\n", 158 + task, 159 + hdr->desc_size, 160 + bcom_task_num_descs(task)); 161 + return -EINVAL; 162 + } 163 + } else { 164 + phys_addr_t start_pa; 165 + 166 + desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa); 167 + if (!desc) 168 + return -ENOMEM; 169 + 170 + tdt->start = start_pa; 171 + tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32)); 172 + } 173 + 174 + var = bcom_task_var(task); 175 + inc = bcom_task_inc(task); 176 + 177 + /* Clear & copy */ 178 + memset(var, 0x00, BCOM_VAR_SIZE); 179 + memset(inc, 0x00, BCOM_INC_SIZE); 180 + 181 + desc_src = (u32 *)(hdr + 1); 182 + var_src = desc_src + hdr->desc_size; 183 + inc_src = var_src + hdr->var_size; 184 + 185 + memcpy(desc, desc_src, hdr->desc_size * sizeof(u32)); 186 + memcpy(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32)); 187 + memcpy(inc, inc_src, hdr->inc_size * sizeof(u32)); 188 + 189 + return 0; 190 + } 191 + EXPORT_SYMBOL_GPL(bcom_load_image); 192 + 193 + void 194 + bcom_set_initiator(int task, int initiator) 195 + { 196 + int i; 197 + int num_descs; 198 + u32 *desc; 199 + int next_drd_has_initiator; 200 + 201 + bcom_set_tcr_initiator(task, initiator); 202 + 203 + /* Just setting tcr is apparently not enough due to some problem */ 204 + /* with it. So we just go thru all the microcode and replace in */ 205 + /* the DRD directly */ 206 + 207 + desc = bcom_task_desc(task); 208 + next_drd_has_initiator = 1; 209 + num_descs = bcom_task_num_descs(task); 210 + 211 + for (i=0; i<num_descs; i++, desc++) { 212 + if (!bcom_desc_is_drd(*desc)) 213 + continue; 214 + if (next_drd_has_initiator) 215 + if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS) 216 + bcom_set_desc_initiator(desc, initiator); 217 + next_drd_has_initiator = !bcom_drd_is_extended(*desc); 218 + } 219 + } 220 + EXPORT_SYMBOL_GPL(bcom_set_initiator); 221 + 222 + 223 + /* Public API */ 224 + 225 + void 226 + bcom_enable(struct bcom_task *tsk) 227 + { 228 + bcom_enable_task(tsk->tasknum); 229 + } 230 + EXPORT_SYMBOL_GPL(bcom_enable); 231 + 232 + void 233 + bcom_disable(struct bcom_task *tsk) 234 + { 235 + bcom_disable_task(tsk->tasknum); 236 + } 237 + EXPORT_SYMBOL_GPL(bcom_disable); 238 + 239 + 240 + /* ======================================================================== */ 241 + /* Engine init/cleanup */ 242 + /* ======================================================================== */ 243 + 244 + /* Function Descriptor table */ 245 + /* this will need to be updated if Freescale changes their task code FDT */ 246 + static u32 fdt_ops[] = { 247 + 0xa0045670, /* FDT[48] - load_acc() */ 248 + 0x80045670, /* FDT[49] - unload_acc() */ 249 + 0x21800000, /* FDT[50] - and() */ 250 + 0x21e00000, /* FDT[51] - or() */ 251 + 0x21500000, /* FDT[52] - xor() */ 252 + 0x21400000, /* FDT[53] - andn() */ 253 + 0x21500000, /* FDT[54] - not() */ 254 + 0x20400000, /* FDT[55] - add() */ 255 + 0x20500000, /* FDT[56] - sub() */ 256 + 0x20800000, /* FDT[57] - lsh() */ 257 + 0x20a00000, /* FDT[58] - rsh() */ 258 + 0xc0170000, /* FDT[59] - crc8() */ 259 + 0xc0145670, /* FDT[60] - crc16() */ 260 + 0xc0345670, /* FDT[61] - crc32() */ 261 + 0xa0076540, /* FDT[62] - endian32() */ 262 + 0xa0000760, /* FDT[63] - endian16() */ 263 + }; 264 + 265 + 266 + static int __devinit 267 + bcom_engine_init(void) 268 + { 269 + int task; 270 + phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa; 271 + unsigned int tdt_size, ctx_size, var_size, fdt_size; 272 + 273 + /* Allocate & clear SRAM zones for FDT, TDTs, contexts and vars/incs */ 274 + tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt); 275 + ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE; 276 + var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE); 277 + fdt_size = BCOM_FDT_SIZE; 278 + 279 + bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa); 280 + bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa); 281 + bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa); 282 + bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa); 283 + 284 + if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) { 285 + printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n"); 286 + 287 + bcom_sram_free(bcom_eng->tdt); 288 + bcom_sram_free(bcom_eng->ctx); 289 + bcom_sram_free(bcom_eng->var); 290 + bcom_sram_free(bcom_eng->fdt); 291 + 292 + return -ENOMEM; 293 + } 294 + 295 + memset(bcom_eng->tdt, 0x00, tdt_size); 296 + memset(bcom_eng->ctx, 0x00, ctx_size); 297 + memset(bcom_eng->var, 0x00, var_size); 298 + memset(bcom_eng->fdt, 0x00, fdt_size); 299 + 300 + /* Copy the FDT for the EU#3 */ 301 + memcpy(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops)); 302 + 303 + /* Initialize Task base structure */ 304 + for (task=0; task<BCOM_MAX_TASKS; task++) 305 + { 306 + out_be16(&bcom_eng->regs->tcr[task], 0); 307 + out_8(&bcom_eng->regs->ipr[task], 0); 308 + 309 + bcom_eng->tdt[task].context = ctx_pa; 310 + bcom_eng->tdt[task].var = var_pa; 311 + bcom_eng->tdt[task].fdt = fdt_pa; 312 + 313 + var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE; 314 + ctx_pa += BCOM_CTX_SIZE; 315 + } 316 + 317 + out_be32(&bcom_eng->regs->taskBar, tdt_pa); 318 + 319 + /* Init 'always' initiator */ 320 + out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS); 321 + 322 + /* Disable COMM Bus Prefetch, apparently it's not reliable yet */ 323 + /* FIXME: This should be done on 5200 and not 5200B ... */ 324 + out_be16(&bcom_eng->regs->PtdCntrl, in_be16(&bcom_eng->regs->PtdCntrl) | 1); 325 + 326 + /* Init lock */ 327 + spin_lock_init(&bcom_eng->lock); 328 + 329 + return 0; 330 + } 331 + 332 + static void 333 + bcom_engine_cleanup(void) 334 + { 335 + int task; 336 + 337 + /* Stop all tasks */ 338 + for (task=0; task<BCOM_MAX_TASKS; task++) 339 + { 340 + out_be16(&bcom_eng->regs->tcr[task], 0); 341 + out_8(&bcom_eng->regs->ipr[task], 0); 342 + } 343 + 344 + out_be32(&bcom_eng->regs->taskBar, 0ul); 345 + 346 + /* Release the SRAM zones */ 347 + bcom_sram_free(bcom_eng->tdt); 348 + bcom_sram_free(bcom_eng->ctx); 349 + bcom_sram_free(bcom_eng->var); 350 + bcom_sram_free(bcom_eng->fdt); 351 + } 352 + 353 + 354 + /* ======================================================================== */ 355 + /* OF platform driver */ 356 + /* ======================================================================== */ 357 + 358 + static int __devinit 359 + mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match) 360 + { 361 + struct device_node *ofn_sram; 362 + struct resource res_bcom; 363 + 364 + int rv; 365 + 366 + /* Inform user we're ok so far */ 367 + printk(KERN_INFO "DMA: MPC52xx BestComm driver\n"); 368 + 369 + /* Get the bestcomm node */ 370 + of_node_get(op->node); 371 + 372 + /* Prepare SRAM */ 373 + ofn_sram = of_find_compatible_node(NULL, "sram", "mpc5200-sram"); 374 + if (!ofn_sram) { 375 + printk(KERN_ERR DRIVER_NAME ": " 376 + "No SRAM found in device tree\n"); 377 + rv = -ENODEV; 378 + goto error_ofput; 379 + } 380 + rv = bcom_sram_init(ofn_sram, DRIVER_NAME); 381 + of_node_put(ofn_sram); 382 + 383 + if (rv) { 384 + printk(KERN_ERR DRIVER_NAME ": " 385 + "Error in SRAM init\n"); 386 + goto error_ofput; 387 + } 388 + 389 + /* Get a clean struct */ 390 + bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL); 391 + if (!bcom_eng) { 392 + printk(KERN_ERR DRIVER_NAME ": " 393 + "Can't allocate state structure\n"); 394 + rv = -ENOMEM; 395 + goto error_sramclean; 396 + } 397 + 398 + /* Save the node */ 399 + bcom_eng->ofnode = op->node; 400 + 401 + /* Get, reserve & map io */ 402 + if (of_address_to_resource(op->node, 0, &res_bcom)) { 403 + printk(KERN_ERR DRIVER_NAME ": " 404 + "Can't get resource\n"); 405 + rv = -EINVAL; 406 + goto error_sramclean; 407 + } 408 + 409 + if (!request_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma), 410 + DRIVER_NAME)) { 411 + printk(KERN_ERR DRIVER_NAME ": " 412 + "Can't request registers region\n"); 413 + rv = -EBUSY; 414 + goto error_sramclean; 415 + } 416 + 417 + bcom_eng->regs_base = res_bcom.start; 418 + bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma)); 419 + if (!bcom_eng->regs) { 420 + printk(KERN_ERR DRIVER_NAME ": " 421 + "Can't map registers\n"); 422 + rv = -ENOMEM; 423 + goto error_release; 424 + } 425 + 426 + /* Now, do the real init */ 427 + rv = bcom_engine_init(); 428 + if (rv) 429 + goto error_unmap; 430 + 431 + /* Done ! */ 432 + printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n", 433 + bcom_eng->regs_base); 434 + 435 + return 0; 436 + 437 + /* Error path */ 438 + error_unmap: 439 + iounmap(bcom_eng->regs); 440 + error_release: 441 + release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma)); 442 + error_sramclean: 443 + kfree(bcom_eng); 444 + bcom_sram_cleanup(); 445 + error_ofput: 446 + of_node_put(op->node); 447 + 448 + printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n"); 449 + 450 + return rv; 451 + } 452 + 453 + 454 + static int 455 + mpc52xx_bcom_remove(struct of_device *op) 456 + { 457 + /* Clean up the engine */ 458 + bcom_engine_cleanup(); 459 + 460 + /* Cleanup SRAM */ 461 + bcom_sram_cleanup(); 462 + 463 + /* Release regs */ 464 + iounmap(bcom_eng->regs); 465 + release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma)); 466 + 467 + /* Release the node */ 468 + of_node_put(bcom_eng->ofnode); 469 + 470 + /* Release memory */ 471 + kfree(bcom_eng); 472 + bcom_eng = NULL; 473 + 474 + return 0; 475 + } 476 + 477 + static struct of_device_id mpc52xx_bcom_of_match[] = { 478 + { 479 + .type = "dma-controller", 480 + .compatible = "mpc5200-bestcomm", 481 + }, 482 + {}, 483 + }; 484 + 485 + MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match); 486 + 487 + 488 + static struct of_platform_driver mpc52xx_bcom_of_platform_driver = { 489 + .owner = THIS_MODULE, 490 + .name = DRIVER_NAME, 491 + .match_table = mpc52xx_bcom_of_match, 492 + .probe = mpc52xx_bcom_probe, 493 + .remove = mpc52xx_bcom_remove, 494 + .driver = { 495 + .name = DRIVER_NAME, 496 + .owner = THIS_MODULE, 497 + }, 498 + }; 499 + 500 + 501 + /* ======================================================================== */ 502 + /* Module */ 503 + /* ======================================================================== */ 504 + 505 + static int __init 506 + mpc52xx_bcom_init(void) 507 + { 508 + return of_register_platform_driver(&mpc52xx_bcom_of_platform_driver); 509 + } 510 + 511 + static void __exit 512 + mpc52xx_bcom_exit(void) 513 + { 514 + of_unregister_platform_driver(&mpc52xx_bcom_of_platform_driver); 515 + } 516 + 517 + /* If we're not a module, we must make sure everything is setup before */ 518 + /* anyone tries to use us ... that's why we use subsys_initcall instead */ 519 + /* of module_init. */ 520 + subsys_initcall(mpc52xx_bcom_init); 521 + module_exit(mpc52xx_bcom_exit); 522 + 523 + MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA"); 524 + MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>"); 525 + MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>"); 526 + MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>"); 527 + MODULE_LICENSE("GPL v2"); 528 +
+190
arch/powerpc/sysdev/bestcomm/bestcomm.h
··· 1 + /* 2 + * Public header for the MPC52xx processor BestComm driver 3 + * 4 + * 5 + * Copyright (C) 2006 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 + * This file is licensed under the terms of the GNU General Public License 12 + * version 2. This program is licensed "as is" without any warranty of any 13 + * kind, whether express or implied. 14 + */ 15 + 16 + #ifndef __BESTCOMM_H__ 17 + #define __BESTCOMM_H__ 18 + 19 + struct bcom_bd; /* defined later on ... */ 20 + 21 + 22 + /* ======================================================================== */ 23 + /* Generic task managment */ 24 + /* ======================================================================== */ 25 + 26 + /** 27 + * struct bcom_task - Structure describing a loaded BestComm task 28 + * 29 + * This structure is never built by the driver it self. It's built and 30 + * filled the intermediate layer of the BestComm API, the task dependent 31 + * support code. 32 + * 33 + * Most likely you don't need to poke around inside this structure. The 34 + * fields are exposed in the header just for the sake of inline functions 35 + */ 36 + struct bcom_task { 37 + unsigned int tasknum; 38 + unsigned int flags; 39 + int irq; 40 + 41 + struct bcom_bd *bd; 42 + phys_addr_t bd_pa; 43 + void **cookie; 44 + unsigned short index; 45 + unsigned short outdex; 46 + unsigned int num_bd; 47 + unsigned int bd_size; 48 + 49 + void* priv; 50 + }; 51 + 52 + #define BCOM_FLAGS_NONE 0x00000000ul 53 + #define BCOM_FLAGS_ENABLE_TASK (1ul << 0) 54 + 55 + /** 56 + * bcom_enable - Enable a BestComm task 57 + * @tsk: The BestComm task structure 58 + * 59 + * This function makes sure the given task is enabled and can be run 60 + * by the BestComm engine as needed 61 + */ 62 + extern void bcom_enable(struct bcom_task *tsk); 63 + 64 + /** 65 + * bcom_disable - Disable a BestComm task 66 + * @tsk: The BestComm task structure 67 + * 68 + * This function disable a given task, making sure it's not executed 69 + * by the BestComm engine. 70 + */ 71 + extern void bcom_disable(struct bcom_task *tsk); 72 + 73 + 74 + /** 75 + * bcom_get_task_irq - Returns the irq number of a BestComm task 76 + * @tsk: The BestComm task structure 77 + */ 78 + static inline int 79 + bcom_get_task_irq(struct bcom_task *tsk) { 80 + return tsk->irq; 81 + } 82 + 83 + /* ======================================================================== */ 84 + /* BD based tasks helpers */ 85 + /* ======================================================================== */ 86 + 87 + /** 88 + * struct bcom_bd - Structure describing a generic BestComm buffer descriptor 89 + * @status: The current status of this buffer. Exact meaning depends on the 90 + * task type 91 + * @data: An array of u32 whose meaning depends on the task type. 92 + */ 93 + struct bcom_bd { 94 + u32 status; 95 + u32 data[1]; /* variable, but at least 1 */ 96 + }; 97 + 98 + #define BCOM_BD_READY 0x40000000ul 99 + 100 + /** _bcom_next_index - Get next input index. 101 + * @tsk: pointer to task structure 102 + * 103 + * Support function; Device drivers should not call this 104 + */ 105 + static inline int 106 + _bcom_next_index(struct bcom_task *tsk) 107 + { 108 + return ((tsk->index + 1) == tsk->num_bd) ? 0 : tsk->index + 1; 109 + } 110 + 111 + /** _bcom_next_outdex - Get next output index. 112 + * @tsk: pointer to task structure 113 + * 114 + * Support function; Device drivers should not call this 115 + */ 116 + static inline int 117 + _bcom_next_outdex(struct bcom_task *tsk) 118 + { 119 + return ((tsk->outdex + 1) == tsk->num_bd) ? 0 : tsk->outdex + 1; 120 + } 121 + 122 + /** 123 + * bcom_queue_empty - Checks if a BestComm task BD queue is empty 124 + * @tsk: The BestComm task structure 125 + */ 126 + static inline int 127 + bcom_queue_empty(struct bcom_task *tsk) 128 + { 129 + return tsk->index == tsk->outdex; 130 + } 131 + 132 + /** 133 + * bcom_queue_full - Checks if a BestComm task BD queue is full 134 + * @tsk: The BestComm task structure 135 + */ 136 + static inline int 137 + bcom_queue_full(struct bcom_task *tsk) 138 + { 139 + return tsk->outdex == _bcom_next_index(tsk); 140 + } 141 + 142 + /** 143 + * bcom_buffer_done - Checks if a BestComm 144 + * @tsk: The BestComm task structure 145 + */ 146 + static inline int 147 + bcom_buffer_done(struct bcom_task *tsk) 148 + { 149 + if (bcom_queue_empty(tsk)) 150 + return 0; 151 + return !(tsk->bd[tsk->outdex].status & BCOM_BD_READY); 152 + } 153 + 154 + /** 155 + * bcom_prepare_next_buffer - clear status of next available buffer. 156 + * @tsk: The BestComm task structure 157 + * 158 + * Returns pointer to next buffer descriptor 159 + */ 160 + static inline struct bcom_bd * 161 + bcom_prepare_next_buffer(struct bcom_task *tsk) 162 + { 163 + tsk->bd[tsk->index].status = 0; /* cleanup last status */ 164 + return &tsk->bd[tsk->index]; 165 + } 166 + 167 + static inline void 168 + bcom_submit_next_buffer(struct bcom_task *tsk, void *cookie) 169 + { 170 + tsk->cookie[tsk->index] = cookie; 171 + mb(); /* ensure the bd is really up-to-date */ 172 + tsk->bd[tsk->index].status |= BCOM_BD_READY; 173 + tsk->index = _bcom_next_index(tsk); 174 + if (tsk->flags & BCOM_FLAGS_ENABLE_TASK) 175 + bcom_enable(tsk); 176 + } 177 + 178 + static inline void * 179 + bcom_retrieve_buffer(struct bcom_task *tsk, u32 *p_status, struct bcom_bd **p_bd) 180 + { 181 + void *cookie = tsk->cookie[tsk->outdex]; 182 + if (p_status) 183 + *p_status = tsk->bd[tsk->outdex].status; 184 + if (p_bd) 185 + *p_bd = &tsk->bd[tsk->outdex]; 186 + tsk->outdex = _bcom_next_outdex(tsk); 187 + return cookie; 188 + } 189 + 190 + #endif /* __BESTCOMM_H__ */
+334
arch/powerpc/sysdev/bestcomm/bestcomm_priv.h
··· 1 + /* 2 + * Private header for the MPC52xx processor BestComm driver 3 + * 4 + * By private, we mean that driver should not use it directly. It's meant 5 + * to be used by the BestComm engine driver itself and by the intermediate 6 + * layer between the core and the drivers. 7 + * 8 + * Copyright (C) 2006 Sylvain Munaut <tnt@246tNt.com> 9 + * Copyright (C) 2005 Varma Electronics Oy, 10 + * ( by Andrey Volkov <avolkov@varma-el.com> ) 11 + * Copyright (C) 2003-2004 MontaVista, Software, Inc. 12 + * ( by Dale Farnsworth <dfarnsworth@mvista.com> ) 13 + * 14 + * This file is licensed under the terms of the GNU General Public License 15 + * version 2. This program is licensed "as is" without any warranty of any 16 + * kind, whether express or implied. 17 + */ 18 + 19 + #ifndef __BESTCOMM_PRIV_H__ 20 + #define __BESTCOMM_PRIV_H__ 21 + 22 + #include <linux/spinlock.h> 23 + #include <linux/of.h> 24 + #include <asm/io.h> 25 + #include <asm/mpc52xx.h> 26 + 27 + #include "sram.h" 28 + 29 + 30 + /* ======================================================================== */ 31 + /* Engine related stuff */ 32 + /* ======================================================================== */ 33 + 34 + /* Zones sizes and needed alignments */ 35 + #define BCOM_MAX_TASKS 16 36 + #define BCOM_MAX_VAR 24 37 + #define BCOM_MAX_INC 8 38 + #define BCOM_MAX_FDT 64 39 + #define BCOM_MAX_CTX 20 40 + #define BCOM_CTX_SIZE (BCOM_MAX_CTX * sizeof(u32)) 41 + #define BCOM_CTX_ALIGN 0x100 42 + #define BCOM_VAR_SIZE (BCOM_MAX_VAR * sizeof(u32)) 43 + #define BCOM_INC_SIZE (BCOM_MAX_INC * sizeof(u32)) 44 + #define BCOM_VAR_ALIGN 0x80 45 + #define BCOM_FDT_SIZE (BCOM_MAX_FDT * sizeof(u32)) 46 + #define BCOM_FDT_ALIGN 0x100 47 + 48 + /** 49 + * struct bcom_tdt - Task Descriptor Table Entry 50 + * 51 + */ 52 + struct bcom_tdt { 53 + u32 start; 54 + u32 stop; 55 + u32 var; 56 + u32 fdt; 57 + u32 exec_status; /* used internally by BestComm engine */ 58 + u32 mvtp; /* used internally by BestComm engine */ 59 + u32 context; 60 + u32 litbase; 61 + }; 62 + 63 + /** 64 + * struct bcom_engine 65 + * 66 + * This holds all info needed globaly to handle the engine 67 + */ 68 + struct bcom_engine { 69 + struct device_node *ofnode; 70 + struct mpc52xx_sdma __iomem *regs; 71 + phys_addr_t regs_base; 72 + 73 + struct bcom_tdt *tdt; 74 + u32 *ctx; 75 + u32 *var; 76 + u32 *fdt; 77 + 78 + spinlock_t lock; 79 + }; 80 + 81 + extern struct bcom_engine *bcom_eng; 82 + 83 + 84 + /* ======================================================================== */ 85 + /* Tasks related stuff */ 86 + /* ======================================================================== */ 87 + 88 + /* Tasks image header */ 89 + #define BCOM_TASK_MAGIC 0x4243544B /* 'BCTK' */ 90 + 91 + struct bcom_task_header { 92 + u32 magic; 93 + u8 desc_size; /* the size fields */ 94 + u8 var_size; /* are given in number */ 95 + u8 inc_size; /* of 32-bits words */ 96 + u8 first_var; 97 + u8 reserved[8]; 98 + }; 99 + 100 + /* Descriptors stucture & co */ 101 + #define BCOM_DESC_NOP 0x000001f8 102 + #define BCOM_LCD_MASK 0x80000000 103 + #define BCOM_DRD_EXTENDED 0x40000000 104 + #define BCOM_DRD_INITIATOR_SHIFT 21 105 + 106 + /* Tasks pragma */ 107 + #define BCOM_PRAGMA_BIT_RSV 7 /* reserved pragma bit */ 108 + #define BCOM_PRAGMA_BIT_PRECISE_INC 6 /* increment 0=when possible, */ 109 + /* 1=iter end */ 110 + #define BCOM_PRAGMA_BIT_RST_ERROR_NO 5 /* don't reset errors on */ 111 + /* task enable */ 112 + #define BCOM_PRAGMA_BIT_PACK 4 /* pack data enable */ 113 + #define BCOM_PRAGMA_BIT_INTEGER 3 /* data alignment */ 114 + /* 0=frac(msb), 1=int(lsb) */ 115 + #define BCOM_PRAGMA_BIT_SPECREAD 2 /* XLB speculative read */ 116 + #define BCOM_PRAGMA_BIT_CW 1 /* write line buffer enable */ 117 + #define BCOM_PRAGMA_BIT_RL 0 /* read line buffer enable */ 118 + 119 + /* Looks like XLB speculative read generates XLB errors when a buffer 120 + * is at the end of the physical memory. i.e. when accessing the 121 + * lasts words, the engine tries to prefetch the next but there is no 122 + * next ... 123 + */ 124 + #define BCOM_STD_PRAGMA ((0 << BCOM_PRAGMA_BIT_RSV) | \ 125 + (0 << BCOM_PRAGMA_BIT_PRECISE_INC) | \ 126 + (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO) | \ 127 + (0 << BCOM_PRAGMA_BIT_PACK) | \ 128 + (0 << BCOM_PRAGMA_BIT_INTEGER) | \ 129 + (0 << BCOM_PRAGMA_BIT_SPECREAD) | \ 130 + (1 << BCOM_PRAGMA_BIT_CW) | \ 131 + (1 << BCOM_PRAGMA_BIT_RL)) 132 + 133 + #define BCOM_PCI_PRAGMA ((0 << BCOM_PRAGMA_BIT_RSV) | \ 134 + (0 << BCOM_PRAGMA_BIT_PRECISE_INC) | \ 135 + (0 << BCOM_PRAGMA_BIT_RST_ERROR_NO) | \ 136 + (0 << BCOM_PRAGMA_BIT_PACK) | \ 137 + (1 << BCOM_PRAGMA_BIT_INTEGER) | \ 138 + (0 << BCOM_PRAGMA_BIT_SPECREAD) | \ 139 + (1 << BCOM_PRAGMA_BIT_CW) | \ 140 + (1 << BCOM_PRAGMA_BIT_RL)) 141 + 142 + #define BCOM_ATA_PRAGMA BCOM_STD_PRAGMA 143 + #define BCOM_CRC16_DP_0_PRAGMA BCOM_STD_PRAGMA 144 + #define BCOM_CRC16_DP_1_PRAGMA BCOM_STD_PRAGMA 145 + #define BCOM_FEC_RX_BD_PRAGMA BCOM_STD_PRAGMA 146 + #define BCOM_FEC_TX_BD_PRAGMA BCOM_STD_PRAGMA 147 + #define BCOM_GEN_DP_0_PRAGMA BCOM_STD_PRAGMA 148 + #define BCOM_GEN_DP_1_PRAGMA BCOM_STD_PRAGMA 149 + #define BCOM_GEN_DP_2_PRAGMA BCOM_STD_PRAGMA 150 + #define BCOM_GEN_DP_3_PRAGMA BCOM_STD_PRAGMA 151 + #define BCOM_GEN_DP_BD_0_PRAGMA BCOM_STD_PRAGMA 152 + #define BCOM_GEN_DP_BD_1_PRAGMA BCOM_STD_PRAGMA 153 + #define BCOM_GEN_RX_BD_PRAGMA BCOM_STD_PRAGMA 154 + #define BCOM_GEN_TX_BD_PRAGMA BCOM_STD_PRAGMA 155 + #define BCOM_GEN_LPC_PRAGMA BCOM_STD_PRAGMA 156 + #define BCOM_PCI_RX_PRAGMA BCOM_PCI_PRAGMA 157 + #define BCOM_PCI_TX_PRAGMA BCOM_PCI_PRAGMA 158 + 159 + /* Initiators number */ 160 + #define BCOM_INITIATOR_ALWAYS 0 161 + #define BCOM_INITIATOR_SCTMR_0 1 162 + #define BCOM_INITIATOR_SCTMR_1 2 163 + #define BCOM_INITIATOR_FEC_RX 3 164 + #define BCOM_INITIATOR_FEC_TX 4 165 + #define BCOM_INITIATOR_ATA_RX 5 166 + #define BCOM_INITIATOR_ATA_TX 6 167 + #define BCOM_INITIATOR_SCPCI_RX 7 168 + #define BCOM_INITIATOR_SCPCI_TX 8 169 + #define BCOM_INITIATOR_PSC3_RX 9 170 + #define BCOM_INITIATOR_PSC3_TX 10 171 + #define BCOM_INITIATOR_PSC2_RX 11 172 + #define BCOM_INITIATOR_PSC2_TX 12 173 + #define BCOM_INITIATOR_PSC1_RX 13 174 + #define BCOM_INITIATOR_PSC1_TX 14 175 + #define BCOM_INITIATOR_SCTMR_2 15 176 + #define BCOM_INITIATOR_SCLPC 16 177 + #define BCOM_INITIATOR_PSC5_RX 17 178 + #define BCOM_INITIATOR_PSC5_TX 18 179 + #define BCOM_INITIATOR_PSC4_RX 19 180 + #define BCOM_INITIATOR_PSC4_TX 20 181 + #define BCOM_INITIATOR_I2C2_RX 21 182 + #define BCOM_INITIATOR_I2C2_TX 22 183 + #define BCOM_INITIATOR_I2C1_RX 23 184 + #define BCOM_INITIATOR_I2C1_TX 24 185 + #define BCOM_INITIATOR_PSC6_RX 25 186 + #define BCOM_INITIATOR_PSC6_TX 26 187 + #define BCOM_INITIATOR_IRDA_RX 25 188 + #define BCOM_INITIATOR_IRDA_TX 26 189 + #define BCOM_INITIATOR_SCTMR_3 27 190 + #define BCOM_INITIATOR_SCTMR_4 28 191 + #define BCOM_INITIATOR_SCTMR_5 29 192 + #define BCOM_INITIATOR_SCTMR_6 30 193 + #define BCOM_INITIATOR_SCTMR_7 31 194 + 195 + /* Initiators priorities */ 196 + #define BCOM_IPR_ALWAYS 7 197 + #define BCOM_IPR_SCTMR_0 2 198 + #define BCOM_IPR_SCTMR_1 2 199 + #define BCOM_IPR_FEC_RX 6 200 + #define BCOM_IPR_FEC_TX 5 201 + #define BCOM_IPR_ATA_RX 4 202 + #define BCOM_IPR_ATA_TX 3 203 + #define BCOM_IPR_SCPCI_RX 2 204 + #define BCOM_IPR_SCPCI_TX 2 205 + #define BCOM_IPR_PSC3_RX 2 206 + #define BCOM_IPR_PSC3_TX 2 207 + #define BCOM_IPR_PSC2_RX 2 208 + #define BCOM_IPR_PSC2_TX 2 209 + #define BCOM_IPR_PSC1_RX 2 210 + #define BCOM_IPR_PSC1_TX 2 211 + #define BCOM_IPR_SCTMR_2 2 212 + #define BCOM_IPR_SCLPC 2 213 + #define BCOM_IPR_PSC5_RX 2 214 + #define BCOM_IPR_PSC5_TX 2 215 + #define BCOM_IPR_PSC4_RX 2 216 + #define BCOM_IPR_PSC4_TX 2 217 + #define BCOM_IPR_I2C2_RX 2 218 + #define BCOM_IPR_I2C2_TX 2 219 + #define BCOM_IPR_I2C1_RX 2 220 + #define BCOM_IPR_I2C1_TX 2 221 + #define BCOM_IPR_PSC6_RX 2 222 + #define BCOM_IPR_PSC6_TX 2 223 + #define BCOM_IPR_IRDA_RX 2 224 + #define BCOM_IPR_IRDA_TX 2 225 + #define BCOM_IPR_SCTMR_3 2 226 + #define BCOM_IPR_SCTMR_4 2 227 + #define BCOM_IPR_SCTMR_5 2 228 + #define BCOM_IPR_SCTMR_6 2 229 + #define BCOM_IPR_SCTMR_7 2 230 + 231 + 232 + /* ======================================================================== */ 233 + /* API */ 234 + /* ======================================================================== */ 235 + 236 + extern struct bcom_task *bcom_task_alloc(int bd_count, int bd_size, int priv_size); 237 + extern void bcom_task_free(struct bcom_task *tsk); 238 + extern int bcom_load_image(int task, u32 *task_image); 239 + extern void bcom_set_initiator(int task, int initiator); 240 + 241 + 242 + #define TASK_ENABLE 0x8000 243 + 244 + static inline void 245 + bcom_enable_task(int task) 246 + { 247 + u16 reg; 248 + reg = in_be16(&bcom_eng->regs->tcr[task]); 249 + out_be16(&bcom_eng->regs->tcr[task], reg | TASK_ENABLE); 250 + } 251 + 252 + static inline void 253 + bcom_disable_task(int task) 254 + { 255 + u16 reg = in_be16(&bcom_eng->regs->tcr[task]); 256 + out_be16(&bcom_eng->regs->tcr[task], reg & ~TASK_ENABLE); 257 + } 258 + 259 + 260 + static inline u32 * 261 + bcom_task_desc(int task) 262 + { 263 + return bcom_sram_pa2va(bcom_eng->tdt[task].start); 264 + } 265 + 266 + static inline int 267 + bcom_task_num_descs(int task) 268 + { 269 + return (bcom_eng->tdt[task].stop - bcom_eng->tdt[task].start)/sizeof(u32) + 1; 270 + } 271 + 272 + static inline u32 * 273 + bcom_task_var(int task) 274 + { 275 + return bcom_sram_pa2va(bcom_eng->tdt[task].var); 276 + } 277 + 278 + static inline u32 * 279 + bcom_task_inc(int task) 280 + { 281 + return &bcom_task_var(task)[BCOM_MAX_VAR]; 282 + } 283 + 284 + 285 + static inline int 286 + bcom_drd_is_extended(u32 desc) 287 + { 288 + return (desc) & BCOM_DRD_EXTENDED; 289 + } 290 + 291 + static inline int 292 + bcom_desc_is_drd(u32 desc) 293 + { 294 + return !(desc & BCOM_LCD_MASK) && desc != BCOM_DESC_NOP; 295 + } 296 + 297 + static inline int 298 + bcom_desc_initiator(u32 desc) 299 + { 300 + return (desc >> BCOM_DRD_INITIATOR_SHIFT) & 0x1f; 301 + } 302 + 303 + static inline void 304 + bcom_set_desc_initiator(u32 *desc, int initiator) 305 + { 306 + *desc = (*desc & ~(0x1f << BCOM_DRD_INITIATOR_SHIFT)) | 307 + ((initiator & 0x1f) << BCOM_DRD_INITIATOR_SHIFT); 308 + } 309 + 310 + 311 + static inline void 312 + bcom_set_task_pragma(int task, int pragma) 313 + { 314 + u32 *fdt = &bcom_eng->tdt[task].fdt; 315 + *fdt = (*fdt & ~0xff) | pragma; 316 + } 317 + 318 + static inline void 319 + bcom_set_task_auto_start(int task, int next_task) 320 + { 321 + u16 __iomem *tcr = &bcom_eng->regs->tcr[task]; 322 + out_be16(tcr, (in_be16(tcr) & ~0xff) | 0x00c0 | next_task); 323 + } 324 + 325 + static inline void 326 + bcom_set_tcr_initiator(int task, int initiator) 327 + { 328 + u16 __iomem *tcr = &bcom_eng->regs->tcr[task]; 329 + out_be16(tcr, (in_be16(tcr) & ~0x1f00) | ((initiator & 0x1f) << 8)); 330 + } 331 + 332 + 333 + #endif /* __BESTCOMM_PRIV_H__ */ 334 +
+177
arch/powerpc/sysdev/bestcomm/sram.c
··· 1 + /* 2 + * Simple memory allocator for on-board SRAM 3 + * 4 + * 5 + * Maintainer : Sylvain Munaut <tnt@246tNt.com> 6 + * 7 + * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com> 8 + * 9 + * This file is licensed under the terms of the GNU General Public License 10 + * version 2. This program is licensed "as is" without any warranty of any 11 + * kind, whether express or implied. 12 + */ 13 + 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/slab.h> 17 + #include <linux/spinlock.h> 18 + #include <linux/string.h> 19 + #include <linux/ioport.h> 20 + #include <linux/of.h> 21 + 22 + #include <asm/io.h> 23 + #include <asm/mmu.h> 24 + 25 + #include "sram.h" 26 + 27 + 28 + /* Struct keeping our 'state' */ 29 + struct bcom_sram *bcom_sram = NULL; 30 + EXPORT_SYMBOL_GPL(bcom_sram); /* needed for inline functions */ 31 + 32 + 33 + /* ======================================================================== */ 34 + /* Public API */ 35 + /* ======================================================================== */ 36 + /* DO NOT USE in interrupts, if needed in irq handler, we should use the 37 + _irqsave version of the spin_locks */ 38 + 39 + int bcom_sram_init(struct device_node *sram_node, char *owner) 40 + { 41 + int rv; 42 + const u32 *regaddr_p; 43 + u64 regaddr64, size64; 44 + unsigned int psize; 45 + 46 + /* Create our state struct */ 47 + if (bcom_sram) { 48 + printk(KERN_ERR "%s: bcom_sram_init: " 49 + "Already initialized !\n", owner); 50 + return -EBUSY; 51 + } 52 + 53 + bcom_sram = kmalloc(sizeof(struct bcom_sram), GFP_KERNEL); 54 + if (!bcom_sram) { 55 + printk(KERN_ERR "%s: bcom_sram_init: " 56 + "Couldn't allocate internal state !\n", owner); 57 + return -ENOMEM; 58 + } 59 + 60 + /* Get address and size of the sram */ 61 + regaddr_p = of_get_address(sram_node, 0, &size64, NULL); 62 + if (!regaddr_p) { 63 + printk(KERN_ERR "%s: bcom_sram_init: " 64 + "Invalid device node !\n", owner); 65 + rv = -EINVAL; 66 + goto error_free; 67 + } 68 + 69 + regaddr64 = of_translate_address(sram_node, regaddr_p); 70 + 71 + bcom_sram->base_phys = (phys_addr_t) regaddr64; 72 + bcom_sram->size = (unsigned int) size64; 73 + 74 + /* Request region */ 75 + if (!request_mem_region(bcom_sram->base_phys, bcom_sram->size, owner)) { 76 + printk(KERN_ERR "%s: bcom_sram_init: " 77 + "Couldn't request region !\n", owner); 78 + rv = -EBUSY; 79 + goto error_free; 80 + } 81 + 82 + /* Map SRAM */ 83 + /* sram is not really __iomem */ 84 + bcom_sram->base_virt = (void*) ioremap(bcom_sram->base_phys, bcom_sram->size); 85 + 86 + if (!bcom_sram->base_virt) { 87 + printk(KERN_ERR "%s: bcom_sram_init: " 88 + "Map error SRAM zone 0x%08lx (0x%0x)!\n", 89 + owner, bcom_sram->base_phys, bcom_sram->size ); 90 + rv = -ENOMEM; 91 + goto error_release; 92 + } 93 + 94 + /* Create an rheap (defaults to 32 bits word alignment) */ 95 + bcom_sram->rh = rh_create(4); 96 + 97 + /* Attach the free zones */ 98 + #if 0 99 + /* Currently disabled ... for future use only */ 100 + reg_addr_p = of_get_property(sram_node, "available", &psize); 101 + #else 102 + regaddr_p = NULL; 103 + psize = 0; 104 + #endif 105 + 106 + if (!regaddr_p || !psize) { 107 + /* Attach the whole zone */ 108 + rh_attach_region(bcom_sram->rh, 0, bcom_sram->size); 109 + } else { 110 + /* Attach each zone independently */ 111 + while (psize >= 2 * sizeof(u32)) { 112 + phys_addr_t zbase = of_translate_address(sram_node, regaddr_p); 113 + rh_attach_region(bcom_sram->rh, zbase - bcom_sram->base_phys, regaddr_p[1]); 114 + regaddr_p += 2; 115 + psize -= 2 * sizeof(u32); 116 + } 117 + } 118 + 119 + /* Init our spinlock */ 120 + spin_lock_init(&bcom_sram->lock); 121 + 122 + return 0; 123 + 124 + error_release: 125 + release_mem_region(bcom_sram->base_phys, bcom_sram->size); 126 + error_free: 127 + kfree(bcom_sram); 128 + bcom_sram = NULL; 129 + 130 + return rv; 131 + } 132 + EXPORT_SYMBOL_GPL(bcom_sram_init); 133 + 134 + void bcom_sram_cleanup(void) 135 + { 136 + /* Free resources */ 137 + if (bcom_sram) { 138 + rh_destroy(bcom_sram->rh); 139 + iounmap((void __iomem *)bcom_sram->base_virt); 140 + release_mem_region(bcom_sram->base_phys, bcom_sram->size); 141 + kfree(bcom_sram); 142 + bcom_sram = NULL; 143 + } 144 + } 145 + EXPORT_SYMBOL_GPL(bcom_sram_cleanup); 146 + 147 + void* bcom_sram_alloc(int size, int align, phys_addr_t *phys) 148 + { 149 + unsigned long offset; 150 + 151 + spin_lock(&bcom_sram->lock); 152 + offset = rh_alloc_align(bcom_sram->rh, size, align, NULL); 153 + spin_unlock(&bcom_sram->lock); 154 + 155 + if (IS_ERR_VALUE(offset)) 156 + return NULL; 157 + 158 + *phys = bcom_sram->base_phys + offset; 159 + return bcom_sram->base_virt + offset; 160 + } 161 + EXPORT_SYMBOL_GPL(bcom_sram_alloc); 162 + 163 + void bcom_sram_free(void *ptr) 164 + { 165 + unsigned long offset; 166 + 167 + if (!ptr) 168 + return; 169 + 170 + offset = ptr - bcom_sram->base_virt; 171 + 172 + spin_lock(&bcom_sram->lock); 173 + rh_free(bcom_sram->rh, offset); 174 + spin_unlock(&bcom_sram->lock); 175 + } 176 + EXPORT_SYMBOL_GPL(bcom_sram_free); 177 +
+54
arch/powerpc/sysdev/bestcomm/sram.h
··· 1 + /* 2 + * Handling of a sram zone for bestcomm 3 + * 4 + * 5 + * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com> 6 + * 7 + * This file is licensed under the terms of the GNU General Public License 8 + * version 2. This program is licensed "as is" without any warranty of any 9 + * kind, whether express or implied. 10 + */ 11 + 12 + #ifndef __BESTCOMM_SRAM_H__ 13 + #define __BESTCOMM_SRAM_H__ 14 + 15 + #include <asm/rheap.h> 16 + #include <asm/mmu.h> 17 + #include <linux/spinlock.h> 18 + 19 + 20 + /* Structure used internally */ 21 + /* The internals are here for the inline functions 22 + * sake, certainly not for the user to mess with ! 23 + */ 24 + struct bcom_sram { 25 + phys_addr_t base_phys; 26 + void *base_virt; 27 + unsigned int size; 28 + rh_info_t *rh; 29 + spinlock_t lock; 30 + }; 31 + 32 + extern struct bcom_sram *bcom_sram; 33 + 34 + 35 + /* Public API */ 36 + extern int bcom_sram_init(struct device_node *sram_node, char *owner); 37 + extern void bcom_sram_cleanup(void); 38 + 39 + extern void* bcom_sram_alloc(int size, int align, phys_addr_t *phys); 40 + extern void bcom_sram_free(void *ptr); 41 + 42 + static inline phys_addr_t bcom_sram_va2pa(void *va) { 43 + return bcom_sram->base_phys + 44 + (unsigned long)(va - bcom_sram->base_virt); 45 + } 46 + 47 + static inline void *bcom_sram_pa2va(phys_addr_t pa) { 48 + return bcom_sram->base_virt + 49 + (unsigned long)(pa - bcom_sram->base_phys); 50 + } 51 + 52 + 53 + #endif /* __BESTCOMM_SRAM_H__ */ 54 +