0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/module.h>
0013 #include <linux/kernel.h>
0014 #include <linux/slab.h>
0015 #include <linux/of.h>
0016 #include <linux/of_address.h>
0017 #include <linux/of_device.h>
0018 #include <linux/of_irq.h>
0019 #include <linux/of_platform.h>
0020 #include <asm/io.h>
0021 #include <asm/irq.h>
0022 #include <asm/mpc52xx.h>
0023
0024 #include <linux/fsl/bestcomm/sram.h>
0025 #include <linux/fsl/bestcomm/bestcomm_priv.h>
0026 #include "linux/fsl/bestcomm/bestcomm.h"
0027
0028 #define DRIVER_NAME "bestcomm-core"
0029
0030
0031 static const struct of_device_id mpc52xx_sram_ids[] = {
0032 { .compatible = "fsl,mpc5200-sram", },
0033 { .compatible = "mpc5200-sram", },
0034 {}
0035 };
0036
0037
0038 struct bcom_engine *bcom_eng = NULL;
0039 EXPORT_SYMBOL_GPL(bcom_eng);
0040
0041
0042
0043
0044
0045
0046
0047 struct bcom_task *
0048 bcom_task_alloc(int bd_count, int bd_size, int priv_size)
0049 {
0050 int i, tasknum = -1;
0051 struct bcom_task *tsk;
0052
0053
0054 if (!bcom_eng)
0055 return NULL;
0056
0057
0058 spin_lock(&bcom_eng->lock);
0059
0060 for (i=0; i<BCOM_MAX_TASKS; i++)
0061 if (!bcom_eng->tdt[i].stop) {
0062 bcom_eng->tdt[i].stop = 0xfffffffful;
0063 tasknum = i;
0064 break;
0065 }
0066
0067 spin_unlock(&bcom_eng->lock);
0068
0069 if (tasknum < 0)
0070 return NULL;
0071
0072
0073 tsk = kzalloc(sizeof(struct bcom_task) + priv_size, GFP_KERNEL);
0074 if (!tsk)
0075 goto error;
0076
0077 tsk->tasknum = tasknum;
0078 if (priv_size)
0079 tsk->priv = (void*)tsk + sizeof(struct bcom_task);
0080
0081
0082 tsk->irq = irq_of_parse_and_map(bcom_eng->ofnode, tsk->tasknum);
0083 if (!tsk->irq)
0084 goto error;
0085
0086
0087 if (bd_count) {
0088 tsk->cookie = kmalloc_array(bd_count, sizeof(void *),
0089 GFP_KERNEL);
0090 if (!tsk->cookie)
0091 goto error;
0092
0093 tsk->bd = bcom_sram_alloc(bd_count * bd_size, 4, &tsk->bd_pa);
0094 if (!tsk->bd)
0095 goto error;
0096 memset_io(tsk->bd, 0x00, bd_count * bd_size);
0097
0098 tsk->num_bd = bd_count;
0099 tsk->bd_size = bd_size;
0100 }
0101
0102 return tsk;
0103
0104 error:
0105 if (tsk) {
0106 if (tsk->irq)
0107 irq_dispose_mapping(tsk->irq);
0108 bcom_sram_free(tsk->bd);
0109 kfree(tsk->cookie);
0110 kfree(tsk);
0111 }
0112
0113 bcom_eng->tdt[tasknum].stop = 0;
0114
0115 return NULL;
0116 }
0117 EXPORT_SYMBOL_GPL(bcom_task_alloc);
0118
0119 void
0120 bcom_task_free(struct bcom_task *tsk)
0121 {
0122
0123 bcom_disable_task(tsk->tasknum);
0124
0125
0126 bcom_eng->tdt[tsk->tasknum].start = 0;
0127 bcom_eng->tdt[tsk->tasknum].stop = 0;
0128
0129
0130 irq_dispose_mapping(tsk->irq);
0131 bcom_sram_free(tsk->bd);
0132 kfree(tsk->cookie);
0133 kfree(tsk);
0134 }
0135 EXPORT_SYMBOL_GPL(bcom_task_free);
0136
0137 int
0138 bcom_load_image(int task, u32 *task_image)
0139 {
0140 struct bcom_task_header *hdr = (struct bcom_task_header *)task_image;
0141 struct bcom_tdt *tdt;
0142 u32 *desc, *var, *inc;
0143 u32 *desc_src, *var_src, *inc_src;
0144
0145
0146 if (hdr->magic != BCOM_TASK_MAGIC) {
0147 printk(KERN_ERR DRIVER_NAME
0148 ": Trying to load invalid microcode\n");
0149 return -EINVAL;
0150 }
0151
0152 if ((task < 0) || (task >= BCOM_MAX_TASKS)) {
0153 printk(KERN_ERR DRIVER_NAME
0154 ": Trying to load invalid task %d\n", task);
0155 return -EINVAL;
0156 }
0157
0158
0159 tdt = &bcom_eng->tdt[task];
0160
0161 if (tdt->start) {
0162 desc = bcom_task_desc(task);
0163 if (hdr->desc_size != bcom_task_num_descs(task)) {
0164 printk(KERN_ERR DRIVER_NAME
0165 ": Trying to reload wrong task image "
0166 "(%d size %d/%d)!\n",
0167 task,
0168 hdr->desc_size,
0169 bcom_task_num_descs(task));
0170 return -EINVAL;
0171 }
0172 } else {
0173 phys_addr_t start_pa;
0174
0175 desc = bcom_sram_alloc(hdr->desc_size * sizeof(u32), 4, &start_pa);
0176 if (!desc)
0177 return -ENOMEM;
0178
0179 tdt->start = start_pa;
0180 tdt->stop = start_pa + ((hdr->desc_size-1) * sizeof(u32));
0181 }
0182
0183 var = bcom_task_var(task);
0184 inc = bcom_task_inc(task);
0185
0186
0187 memset_io(var, 0x00, BCOM_VAR_SIZE);
0188 memset_io(inc, 0x00, BCOM_INC_SIZE);
0189
0190 desc_src = (u32 *)(hdr + 1);
0191 var_src = desc_src + hdr->desc_size;
0192 inc_src = var_src + hdr->var_size;
0193
0194 memcpy_toio(desc, desc_src, hdr->desc_size * sizeof(u32));
0195 memcpy_toio(var + hdr->first_var, var_src, hdr->var_size * sizeof(u32));
0196 memcpy_toio(inc, inc_src, hdr->inc_size * sizeof(u32));
0197
0198 return 0;
0199 }
0200 EXPORT_SYMBOL_GPL(bcom_load_image);
0201
0202 void
0203 bcom_set_initiator(int task, int initiator)
0204 {
0205 int i;
0206 int num_descs;
0207 u32 *desc;
0208 int next_drd_has_initiator;
0209
0210 bcom_set_tcr_initiator(task, initiator);
0211
0212
0213
0214
0215
0216 desc = bcom_task_desc(task);
0217 next_drd_has_initiator = 1;
0218 num_descs = bcom_task_num_descs(task);
0219
0220 for (i=0; i<num_descs; i++, desc++) {
0221 if (!bcom_desc_is_drd(*desc))
0222 continue;
0223 if (next_drd_has_initiator)
0224 if (bcom_desc_initiator(*desc) != BCOM_INITIATOR_ALWAYS)
0225 bcom_set_desc_initiator(desc, initiator);
0226 next_drd_has_initiator = !bcom_drd_is_extended(*desc);
0227 }
0228 }
0229 EXPORT_SYMBOL_GPL(bcom_set_initiator);
0230
0231
0232
0233
0234 void
0235 bcom_enable(struct bcom_task *tsk)
0236 {
0237 bcom_enable_task(tsk->tasknum);
0238 }
0239 EXPORT_SYMBOL_GPL(bcom_enable);
0240
0241 void
0242 bcom_disable(struct bcom_task *tsk)
0243 {
0244 bcom_disable_task(tsk->tasknum);
0245 }
0246 EXPORT_SYMBOL_GPL(bcom_disable);
0247
0248
0249
0250
0251
0252
0253
0254
0255 static u32 fdt_ops[] = {
0256 0xa0045670,
0257 0x80045670,
0258 0x21800000,
0259 0x21e00000,
0260 0x21500000,
0261 0x21400000,
0262 0x21500000,
0263 0x20400000,
0264 0x20500000,
0265 0x20800000,
0266 0x20a00000,
0267 0xc0170000,
0268 0xc0145670,
0269 0xc0345670,
0270 0xa0076540,
0271 0xa0000760,
0272 };
0273
0274
0275 static int bcom_engine_init(void)
0276 {
0277 int task;
0278 phys_addr_t tdt_pa, ctx_pa, var_pa, fdt_pa;
0279 unsigned int tdt_size, ctx_size, var_size, fdt_size;
0280
0281
0282 tdt_size = BCOM_MAX_TASKS * sizeof(struct bcom_tdt);
0283 ctx_size = BCOM_MAX_TASKS * BCOM_CTX_SIZE;
0284 var_size = BCOM_MAX_TASKS * (BCOM_VAR_SIZE + BCOM_INC_SIZE);
0285 fdt_size = BCOM_FDT_SIZE;
0286
0287 bcom_eng->tdt = bcom_sram_alloc(tdt_size, sizeof(u32), &tdt_pa);
0288 bcom_eng->ctx = bcom_sram_alloc(ctx_size, BCOM_CTX_ALIGN, &ctx_pa);
0289 bcom_eng->var = bcom_sram_alloc(var_size, BCOM_VAR_ALIGN, &var_pa);
0290 bcom_eng->fdt = bcom_sram_alloc(fdt_size, BCOM_FDT_ALIGN, &fdt_pa);
0291
0292 if (!bcom_eng->tdt || !bcom_eng->ctx || !bcom_eng->var || !bcom_eng->fdt) {
0293 printk(KERN_ERR "DMA: SRAM alloc failed in engine init !\n");
0294
0295 bcom_sram_free(bcom_eng->tdt);
0296 bcom_sram_free(bcom_eng->ctx);
0297 bcom_sram_free(bcom_eng->var);
0298 bcom_sram_free(bcom_eng->fdt);
0299
0300 return -ENOMEM;
0301 }
0302
0303 memset_io(bcom_eng->tdt, 0x00, tdt_size);
0304 memset_io(bcom_eng->ctx, 0x00, ctx_size);
0305 memset_io(bcom_eng->var, 0x00, var_size);
0306 memset_io(bcom_eng->fdt, 0x00, fdt_size);
0307
0308
0309 memcpy_toio(&bcom_eng->fdt[48], fdt_ops, sizeof(fdt_ops));
0310
0311
0312 for (task=0; task<BCOM_MAX_TASKS; task++)
0313 {
0314 out_be16(&bcom_eng->regs->tcr[task], 0);
0315 out_8(&bcom_eng->regs->ipr[task], 0);
0316
0317 bcom_eng->tdt[task].context = ctx_pa;
0318 bcom_eng->tdt[task].var = var_pa;
0319 bcom_eng->tdt[task].fdt = fdt_pa;
0320
0321 var_pa += BCOM_VAR_SIZE + BCOM_INC_SIZE;
0322 ctx_pa += BCOM_CTX_SIZE;
0323 }
0324
0325 out_be32(&bcom_eng->regs->taskBar, tdt_pa);
0326
0327
0328 out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ALWAYS], BCOM_IPR_ALWAYS);
0329
0330
0331 if ((mfspr(SPRN_SVR) & MPC5200_SVR_MASK) == MPC5200_SVR)
0332 bcom_disable_prefetch();
0333
0334
0335 spin_lock_init(&bcom_eng->lock);
0336
0337 return 0;
0338 }
0339
0340 static void
0341 bcom_engine_cleanup(void)
0342 {
0343 int task;
0344
0345
0346 for (task=0; task<BCOM_MAX_TASKS; task++)
0347 {
0348 out_be16(&bcom_eng->regs->tcr[task], 0);
0349 out_8(&bcom_eng->regs->ipr[task], 0);
0350 }
0351
0352 out_be32(&bcom_eng->regs->taskBar, 0ul);
0353
0354
0355 bcom_sram_free(bcom_eng->tdt);
0356 bcom_sram_free(bcom_eng->ctx);
0357 bcom_sram_free(bcom_eng->var);
0358 bcom_sram_free(bcom_eng->fdt);
0359 }
0360
0361
0362
0363
0364
0365
0366 static int mpc52xx_bcom_probe(struct platform_device *op)
0367 {
0368 struct device_node *ofn_sram;
0369 struct resource res_bcom;
0370
0371 int rv;
0372
0373
0374 printk(KERN_INFO "DMA: MPC52xx BestComm driver\n");
0375
0376
0377 of_node_get(op->dev.of_node);
0378
0379
0380 ofn_sram = of_find_matching_node(NULL, mpc52xx_sram_ids);
0381 if (!ofn_sram) {
0382 printk(KERN_ERR DRIVER_NAME ": "
0383 "No SRAM found in device tree\n");
0384 rv = -ENODEV;
0385 goto error_ofput;
0386 }
0387 rv = bcom_sram_init(ofn_sram, DRIVER_NAME);
0388 of_node_put(ofn_sram);
0389
0390 if (rv) {
0391 printk(KERN_ERR DRIVER_NAME ": "
0392 "Error in SRAM init\n");
0393 goto error_ofput;
0394 }
0395
0396
0397 bcom_eng = kzalloc(sizeof(struct bcom_engine), GFP_KERNEL);
0398 if (!bcom_eng) {
0399 rv = -ENOMEM;
0400 goto error_sramclean;
0401 }
0402
0403
0404 bcom_eng->ofnode = op->dev.of_node;
0405
0406
0407 if (of_address_to_resource(op->dev.of_node, 0, &res_bcom)) {
0408 printk(KERN_ERR DRIVER_NAME ": "
0409 "Can't get resource\n");
0410 rv = -EINVAL;
0411 goto error_sramclean;
0412 }
0413
0414 if (!request_mem_region(res_bcom.start, resource_size(&res_bcom),
0415 DRIVER_NAME)) {
0416 printk(KERN_ERR DRIVER_NAME ": "
0417 "Can't request registers region\n");
0418 rv = -EBUSY;
0419 goto error_sramclean;
0420 }
0421
0422 bcom_eng->regs_base = res_bcom.start;
0423 bcom_eng->regs = ioremap(res_bcom.start, sizeof(struct mpc52xx_sdma));
0424 if (!bcom_eng->regs) {
0425 printk(KERN_ERR DRIVER_NAME ": "
0426 "Can't map registers\n");
0427 rv = -ENOMEM;
0428 goto error_release;
0429 }
0430
0431
0432 rv = bcom_engine_init();
0433 if (rv)
0434 goto error_unmap;
0435
0436
0437 printk(KERN_INFO "DMA: MPC52xx BestComm engine @%08lx ok !\n",
0438 (long)bcom_eng->regs_base);
0439
0440 return 0;
0441
0442
0443 error_unmap:
0444 iounmap(bcom_eng->regs);
0445 error_release:
0446 release_mem_region(res_bcom.start, sizeof(struct mpc52xx_sdma));
0447 error_sramclean:
0448 kfree(bcom_eng);
0449 bcom_sram_cleanup();
0450 error_ofput:
0451 of_node_put(op->dev.of_node);
0452
0453 printk(KERN_ERR "DMA: MPC52xx BestComm init failed !\n");
0454
0455 return rv;
0456 }
0457
0458
0459 static int mpc52xx_bcom_remove(struct platform_device *op)
0460 {
0461
0462 bcom_engine_cleanup();
0463
0464
0465 bcom_sram_cleanup();
0466
0467
0468 iounmap(bcom_eng->regs);
0469 release_mem_region(bcom_eng->regs_base, sizeof(struct mpc52xx_sdma));
0470
0471
0472 of_node_put(bcom_eng->ofnode);
0473
0474
0475 kfree(bcom_eng);
0476 bcom_eng = NULL;
0477
0478 return 0;
0479 }
0480
0481 static const struct of_device_id mpc52xx_bcom_of_match[] = {
0482 { .compatible = "fsl,mpc5200-bestcomm", },
0483 { .compatible = "mpc5200-bestcomm", },
0484 {},
0485 };
0486
0487 MODULE_DEVICE_TABLE(of, mpc52xx_bcom_of_match);
0488
0489
0490 static struct platform_driver mpc52xx_bcom_of_platform_driver = {
0491 .probe = mpc52xx_bcom_probe,
0492 .remove = mpc52xx_bcom_remove,
0493 .driver = {
0494 .name = DRIVER_NAME,
0495 .of_match_table = mpc52xx_bcom_of_match,
0496 },
0497 };
0498
0499
0500
0501
0502
0503
0504 static int __init
0505 mpc52xx_bcom_init(void)
0506 {
0507 return platform_driver_register(&mpc52xx_bcom_of_platform_driver);
0508 }
0509
0510 static void __exit
0511 mpc52xx_bcom_exit(void)
0512 {
0513 platform_driver_unregister(&mpc52xx_bcom_of_platform_driver);
0514 }
0515
0516
0517
0518
0519 subsys_initcall(mpc52xx_bcom_init);
0520 module_exit(mpc52xx_bcom_exit);
0521
0522 MODULE_DESCRIPTION("Freescale MPC52xx BestComm DMA");
0523 MODULE_AUTHOR("Sylvain Munaut <tnt@246tNt.com>");
0524 MODULE_AUTHOR("Andrey Volkov <avolkov@varma-el.com>");
0525 MODULE_AUTHOR("Dale Farnsworth <dfarnsworth@mvista.com>");
0526 MODULE_LICENSE("GPL v2");