diff options
author | Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> | 2010-02-15 13:03:33 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-02-15 13:03:33 -0500 |
commit | c8c99699bd25d8b238ba75d2530d1be90e3c39ea (patch) | |
tree | 50d4b5fa730c3f1a77c96ebb4abd7593c0fcb7e0 /arch/arm/plat-omap/mcbsp.c | |
parent | 8ea3200f1de1c3d8f3c884a704107fb1e7449547 (diff) |
omap: McBSP: Introduce caching in register write operations
Determine cache size required per McBSP port at init time, based on
processor type running on.
Allocate space for storing cached copies of McBSP register values at
port request.
Modify omap_msbcp_write() function to update the cache with every
register write operation.
Modify omap_mcbsp_read() to support reading from cache or hardware.
Update MCBSP_READ() macro for modified omap_mcbsp_read() function API.
Introduce a new macro that reads from the cache.
Tested on OMAP1510 based Amstrad Delta using linux-omap for-next, commit
fb7380d70e041e4b3892f6b19dff7efb609d15a4 (2.6.33-rc3+ dated 2010-01-11).
Compile-tested with: omap_perseus2_730_defconfig, omap_generic_1610_defconfig,
omap_generic_2420_defconfig, omap_2430sdp_defconfig, omap_3430sdp_defconfig,
omap_4430sdp_defconfig with CONFIG_OMAP_MCBSP=y selected.
Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
Acked-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Acked-by: Jarkko Nikula <jhnikula@gmail.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/plat-omap/mcbsp.c')
-rw-r--r-- | arch/arm/plat-omap/mcbsp.c | 77 |
1 files changed, 53 insertions, 24 deletions
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index f8245f25825b..61e440a0f7cd 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c | |||
@@ -28,28 +28,42 @@ | |||
28 | #include <plat/mcbsp.h> | 28 | #include <plat/mcbsp.h> |
29 | 29 | ||
30 | struct omap_mcbsp **mcbsp_ptr; | 30 | struct omap_mcbsp **mcbsp_ptr; |
31 | int omap_mcbsp_count; | 31 | int omap_mcbsp_count, omap_mcbsp_cache_size; |
32 | 32 | ||
33 | void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) | 33 | void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) |
34 | { | 34 | { |
35 | if (cpu_class_is_omap1() || cpu_is_omap2420()) | 35 | if (cpu_class_is_omap1()) { |
36 | ((u16 *)mcbsp->reg_cache)[reg / sizeof(u16)] = (u16)val; | ||
36 | __raw_writew((u16)val, mcbsp->io_base + reg); | 37 | __raw_writew((u16)val, mcbsp->io_base + reg); |
37 | else | 38 | } else if (cpu_is_omap2420()) { |
39 | ((u16 *)mcbsp->reg_cache)[reg / sizeof(u32)] = (u16)val; | ||
40 | __raw_writew((u16)val, mcbsp->io_base + reg); | ||
41 | } else { | ||
42 | ((u32 *)mcbsp->reg_cache)[reg / sizeof(u32)] = val; | ||
38 | __raw_writel(val, mcbsp->io_base + reg); | 43 | __raw_writel(val, mcbsp->io_base + reg); |
44 | } | ||
39 | } | 45 | } |
40 | 46 | ||
41 | int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg) | 47 | int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache) |
42 | { | 48 | { |
43 | if (cpu_class_is_omap1() || cpu_is_omap2420()) | 49 | if (cpu_class_is_omap1()) { |
44 | return __raw_readw(mcbsp->io_base + reg); | 50 | return !from_cache ? __raw_readw(mcbsp->io_base + reg) : |
45 | else | 51 | ((u16 *)mcbsp->reg_cache)[reg / sizeof(u16)]; |
46 | return __raw_readl(mcbsp->io_base + reg); | 52 | } else if (cpu_is_omap2420()) { |
53 | return !from_cache ? __raw_readw(mcbsp->io_base + reg) : | ||
54 | ((u16 *)mcbsp->reg_cache)[reg / sizeof(u32)]; | ||
55 | } else { | ||
56 | return !from_cache ? __raw_readl(mcbsp->io_base + reg) : | ||
57 | ((u32 *)mcbsp->reg_cache)[reg / sizeof(u32)]; | ||
58 | } | ||
47 | } | 59 | } |
48 | 60 | ||
49 | #define MCBSP_READ(mcbsp, reg) \ | 61 | #define MCBSP_READ(mcbsp, reg) \ |
50 | omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg) | 62 | omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) |
51 | #define MCBSP_WRITE(mcbsp, reg, val) \ | 63 | #define MCBSP_WRITE(mcbsp, reg, val) \ |
52 | omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) | 64 | omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) |
65 | #define MCBSP_READ_CACHE(mcbsp, reg) \ | ||
66 | omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1) | ||
53 | 67 | ||
54 | #define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count) | 68 | #define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count) |
55 | #define id_to_mcbsp_ptr(id) mcbsp_ptr[id]; | 69 | #define id_to_mcbsp_ptr(id) mcbsp_ptr[id]; |
@@ -383,6 +397,7 @@ EXPORT_SYMBOL(omap_mcbsp_set_io_type); | |||
383 | int omap_mcbsp_request(unsigned int id) | 397 | int omap_mcbsp_request(unsigned int id) |
384 | { | 398 | { |
385 | struct omap_mcbsp *mcbsp; | 399 | struct omap_mcbsp *mcbsp; |
400 | void *reg_cache; | ||
386 | int err; | 401 | int err; |
387 | 402 | ||
388 | if (!omap_mcbsp_check_valid_id(id)) { | 403 | if (!omap_mcbsp_check_valid_id(id)) { |
@@ -391,15 +406,21 @@ int omap_mcbsp_request(unsigned int id) | |||
391 | } | 406 | } |
392 | mcbsp = id_to_mcbsp_ptr(id); | 407 | mcbsp = id_to_mcbsp_ptr(id); |
393 | 408 | ||
409 | reg_cache = kzalloc(omap_mcbsp_cache_size, GFP_KERNEL); | ||
410 | if (!reg_cache) { | ||
411 | return -ENOMEM; | ||
412 | } | ||
413 | |||
394 | spin_lock(&mcbsp->lock); | 414 | spin_lock(&mcbsp->lock); |
395 | if (!mcbsp->free) { | 415 | if (!mcbsp->free) { |
396 | dev_err(mcbsp->dev, "McBSP%d is currently in use\n", | 416 | dev_err(mcbsp->dev, "McBSP%d is currently in use\n", |
397 | mcbsp->id); | 417 | mcbsp->id); |
398 | spin_unlock(&mcbsp->lock); | 418 | err = -EBUSY; |
399 | return -EBUSY; | 419 | goto err_kfree; |
400 | } | 420 | } |
401 | 421 | ||
402 | mcbsp->free = 0; | 422 | mcbsp->free = 0; |
423 | mcbsp->reg_cache = reg_cache; | ||
403 | spin_unlock(&mcbsp->lock); | 424 | spin_unlock(&mcbsp->lock); |
404 | 425 | ||
405 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) | 426 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) |
@@ -427,7 +448,7 @@ int omap_mcbsp_request(unsigned int id) | |||
427 | dev_err(mcbsp->dev, "Unable to request TX IRQ %d " | 448 | dev_err(mcbsp->dev, "Unable to request TX IRQ %d " |
428 | "for McBSP%d\n", mcbsp->tx_irq, | 449 | "for McBSP%d\n", mcbsp->tx_irq, |
429 | mcbsp->id); | 450 | mcbsp->id); |
430 | goto error; | 451 | goto err_clk_disable; |
431 | } | 452 | } |
432 | 453 | ||
433 | init_completion(&mcbsp->rx_irq_completion); | 454 | init_completion(&mcbsp->rx_irq_completion); |
@@ -437,16 +458,16 @@ int omap_mcbsp_request(unsigned int id) | |||
437 | dev_err(mcbsp->dev, "Unable to request RX IRQ %d " | 458 | dev_err(mcbsp->dev, "Unable to request RX IRQ %d " |
438 | "for McBSP%d\n", mcbsp->rx_irq, | 459 | "for McBSP%d\n", mcbsp->rx_irq, |
439 | mcbsp->id); | 460 | mcbsp->id); |
440 | goto tx_irq; | 461 | goto err_free_irq; |
441 | } | 462 | } |
442 | } | 463 | } |
443 | 464 | ||
444 | return 0; | 465 | return 0; |
445 | tx_irq: | 466 | err_free_irq: |
446 | free_irq(mcbsp->tx_irq, (void *)mcbsp); | 467 | free_irq(mcbsp->tx_irq, (void *)mcbsp); |
447 | error: | 468 | err_clk_disable: |
448 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) | 469 | if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) |
449 | mcbsp->pdata->ops->free(id); | 470 | mcbsp->pdata->ops->free(id); |
450 | 471 | ||
451 | /* Do procedure specific to omap34xx arch, if applicable */ | 472 | /* Do procedure specific to omap34xx arch, if applicable */ |
452 | omap34xx_mcbsp_free(mcbsp); | 473 | omap34xx_mcbsp_free(mcbsp); |
@@ -454,7 +475,12 @@ error: | |||
454 | clk_disable(mcbsp->fclk); | 475 | clk_disable(mcbsp->fclk); |
455 | clk_disable(mcbsp->iclk); | 476 | clk_disable(mcbsp->iclk); |
456 | 477 | ||
478 | spin_lock(&mcbsp->lock); | ||
457 | mcbsp->free = 1; | 479 | mcbsp->free = 1; |
480 | mcbsp->reg_cache = NULL; | ||
481 | err_kfree: | ||
482 | spin_unlock(&mcbsp->lock); | ||
483 | kfree(reg_cache); | ||
458 | 484 | ||
459 | return err; | 485 | return err; |
460 | } | 486 | } |
@@ -463,6 +489,7 @@ EXPORT_SYMBOL(omap_mcbsp_request); | |||
463 | void omap_mcbsp_free(unsigned int id) | 489 | void omap_mcbsp_free(unsigned int id) |
464 | { | 490 | { |
465 | struct omap_mcbsp *mcbsp; | 491 | struct omap_mcbsp *mcbsp; |
492 | void *reg_cache; | ||
466 | 493 | ||
467 | if (!omap_mcbsp_check_valid_id(id)) { | 494 | if (!omap_mcbsp_check_valid_id(id)) { |
468 | printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); | 495 | printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); |
@@ -485,16 +512,18 @@ void omap_mcbsp_free(unsigned int id) | |||
485 | free_irq(mcbsp->tx_irq, (void *)mcbsp); | 512 | free_irq(mcbsp->tx_irq, (void *)mcbsp); |
486 | } | 513 | } |
487 | 514 | ||
488 | spin_lock(&mcbsp->lock); | 515 | reg_cache = mcbsp->reg_cache; |
489 | if (mcbsp->free) { | ||
490 | dev_err(mcbsp->dev, "McBSP%d was not reserved\n", | ||
491 | mcbsp->id); | ||
492 | spin_unlock(&mcbsp->lock); | ||
493 | return; | ||
494 | } | ||
495 | 516 | ||
496 | mcbsp->free = 1; | 517 | spin_lock(&mcbsp->lock); |
518 | if (mcbsp->free) | ||
519 | dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); | ||
520 | else | ||
521 | mcbsp->free = 1; | ||
522 | mcbsp->reg_cache = NULL; | ||
497 | spin_unlock(&mcbsp->lock); | 523 | spin_unlock(&mcbsp->lock); |
524 | |||
525 | if (reg_cache) | ||
526 | kfree(reg_cache); | ||
498 | } | 527 | } |
499 | EXPORT_SYMBOL(omap_mcbsp_free); | 528 | EXPORT_SYMBOL(omap_mcbsp_free); |
500 | 529 | ||