diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
| -rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 164 |
1 files changed, 64 insertions, 100 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 633b216a8b26..d8c8545875b1 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | #include <linux/mutex.h> | 45 | #include <linux/mutex.h> |
| 46 | #include <linux/bootmem.h> | 46 | #include <linux/bootmem.h> |
| 47 | 47 | ||
| 48 | #include <plat/common.h> | ||
| 48 | #include <plat/cpu.h> | 49 | #include <plat/cpu.h> |
| 49 | #include <plat/clockdomain.h> | 50 | #include <plat/clockdomain.h> |
| 50 | #include <plat/powerdomain.h> | 51 | #include <plat/powerdomain.h> |
| @@ -210,6 +211,32 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v) | |||
| 210 | } | 211 | } |
| 211 | 212 | ||
| 212 | /** | 213 | /** |
| 214 | * _set_module_autoidle: set the OCP_SYSCONFIG AUTOIDLE field in @v | ||
| 215 | * @oh: struct omap_hwmod * | ||
| 216 | * @autoidle: desired AUTOIDLE bitfield value (0 or 1) | ||
| 217 | * @v: pointer to register contents to modify | ||
| 218 | * | ||
| 219 | * Update the module autoidle bit in @v to be @autoidle for the @oh | ||
| 220 | * hwmod. The autoidle bit controls whether the module can gate | ||
| 221 | * internal clocks automatically when it isn't doing anything; the | ||
| 222 | * exact function of this bit varies on a per-module basis. This | ||
| 223 | * function does not write to the hardware. Returns -EINVAL upon | ||
| 224 | * error or 0 upon success. | ||
| 225 | */ | ||
| 226 | static int _set_module_autoidle(struct omap_hwmod *oh, u8 autoidle, | ||
| 227 | u32 *v) | ||
| 228 | { | ||
| 229 | if (!oh->sysconfig || | ||
| 230 | !(oh->sysconfig->sysc_flags & SYSC_HAS_AUTOIDLE)) | ||
| 231 | return -EINVAL; | ||
| 232 | |||
| 233 | *v &= ~SYSC_AUTOIDLE_MASK; | ||
| 234 | *v |= autoidle << SYSC_AUTOIDLE_SHIFT; | ||
| 235 | |||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | /** | ||
| 213 | * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware | 240 | * _enable_wakeup: set OCP_SYSCONFIG.ENAWAKEUP bit in the hardware |
| 214 | * @oh: struct omap_hwmod * | 241 | * @oh: struct omap_hwmod * |
| 215 | * | 242 | * |
| @@ -326,6 +353,9 @@ static int _init_main_clk(struct omap_hwmod *oh) | |||
| 326 | ret = -EINVAL; | 353 | ret = -EINVAL; |
| 327 | oh->_clk = c; | 354 | oh->_clk = c; |
| 328 | 355 | ||
| 356 | WARN(!c->clkdm, "omap_hwmod: %s: missing clockdomain for %s.\n", | ||
| 357 | oh->clkdev_con_id, c->name); | ||
| 358 | |||
| 329 | return ret; | 359 | return ret; |
| 330 | } | 360 | } |
| 331 | 361 | ||
| @@ -557,8 +587,19 @@ static void _sysc_enable(struct omap_hwmod *oh) | |||
| 557 | _set_master_standbymode(oh, idlemode, &v); | 587 | _set_master_standbymode(oh, idlemode, &v); |
| 558 | } | 588 | } |
| 559 | 589 | ||
| 560 | /* XXX OCP AUTOIDLE bit? */ | 590 | if (oh->sysconfig->sysc_flags & SYSC_HAS_AUTOIDLE) { |
| 591 | idlemode = (oh->flags & HWMOD_NO_OCP_AUTOIDLE) ? | ||
| 592 | 0 : 1; | ||
| 593 | _set_module_autoidle(oh, idlemode, &v); | ||
| 594 | } | ||
| 595 | |||
| 596 | /* XXX OCP ENAWAKEUP bit? */ | ||
| 561 | 597 | ||
| 598 | /* | ||
| 599 | * XXX The clock framework should handle this, by | ||
| 600 | * calling into this code. But this must wait until the | ||
| 601 | * clock structures are tagged with omap_hwmod entries | ||
| 602 | */ | ||
| 562 | if (oh->flags & HWMOD_SET_DEFAULT_CLOCKACT && | 603 | if (oh->flags & HWMOD_SET_DEFAULT_CLOCKACT && |
| 563 | oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY) | 604 | oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY) |
| 564 | _set_clockactivity(oh, oh->sysconfig->clockact, &v); | 605 | _set_clockactivity(oh, oh->sysconfig->clockact, &v); |
| @@ -622,7 +663,8 @@ static void _sysc_shutdown(struct omap_hwmod *oh) | |||
| 622 | if (oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE) | 663 | if (oh->sysconfig->sysc_flags & SYSC_HAS_MIDLEMODE) |
| 623 | _set_master_standbymode(oh, HWMOD_IDLEMODE_FORCE, &v); | 664 | _set_master_standbymode(oh, HWMOD_IDLEMODE_FORCE, &v); |
| 624 | 665 | ||
| 625 | /* XXX clear OCP AUTOIDLE bit? */ | 666 | if (oh->sysconfig->sysc_flags & SYSC_HAS_AUTOIDLE) |
| 667 | _set_module_autoidle(oh, 1, &v); | ||
| 626 | 668 | ||
| 627 | _write_sysconfig(v, oh); | 669 | _write_sysconfig(v, oh); |
| 628 | } | 670 | } |
| @@ -736,7 +778,7 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
| 736 | static int _reset(struct omap_hwmod *oh) | 778 | static int _reset(struct omap_hwmod *oh) |
| 737 | { | 779 | { |
| 738 | u32 r, v; | 780 | u32 r, v; |
| 739 | int c; | 781 | int c = 0; |
| 740 | 782 | ||
| 741 | if (!oh->sysconfig || | 783 | if (!oh->sysconfig || |
| 742 | !(oh->sysconfig->sysc_flags & SYSC_HAS_SOFTRESET) || | 784 | !(oh->sysconfig->sysc_flags & SYSC_HAS_SOFTRESET) || |
| @@ -758,13 +800,9 @@ static int _reset(struct omap_hwmod *oh) | |||
| 758 | return r; | 800 | return r; |
| 759 | _write_sysconfig(v, oh); | 801 | _write_sysconfig(v, oh); |
| 760 | 802 | ||
| 761 | c = 0; | 803 | omap_test_timeout((omap_hwmod_readl(oh, oh->sysconfig->syss_offs) & |
| 762 | while (c < MAX_MODULE_RESET_WAIT && | 804 | SYSS_RESETDONE_MASK), |
| 763 | !(omap_hwmod_readl(oh, oh->sysconfig->syss_offs) & | 805 | MAX_MODULE_RESET_WAIT, c); |
| 764 | SYSS_RESETDONE_MASK)) { | ||
| 765 | udelay(1); | ||
| 766 | c++; | ||
| 767 | } | ||
| 768 | 806 | ||
| 769 | if (c == MAX_MODULE_RESET_WAIT) | 807 | if (c == MAX_MODULE_RESET_WAIT) |
| 770 | WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n", | 808 | WARN(1, "omap_hwmod: %s: failed to reset in %d usec\n", |
| @@ -884,33 +922,6 @@ static int _shutdown(struct omap_hwmod *oh) | |||
| 884 | } | 922 | } |
| 885 | 923 | ||
| 886 | /** | 924 | /** |
| 887 | * _write_clockact_lock - set the module's clockactivity bits | ||
| 888 | * @oh: struct omap_hwmod * | ||
| 889 | * @clockact: CLOCKACTIVITY field bits | ||
| 890 | * | ||
| 891 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh | ||
| 892 | * OCP_SYSCONFIG register. Returns -EINVAL if the hwmod is in the | ||
| 893 | * wrong state or returns 0. | ||
| 894 | */ | ||
| 895 | static int _write_clockact_lock(struct omap_hwmod *oh, u8 clockact) | ||
| 896 | { | ||
| 897 | u32 v; | ||
| 898 | |||
| 899 | if (!oh->sysconfig || | ||
| 900 | !(oh->sysconfig->sysc_flags & SYSC_HAS_CLOCKACTIVITY)) | ||
| 901 | return -EINVAL; | ||
| 902 | |||
| 903 | mutex_lock(&omap_hwmod_mutex); | ||
| 904 | v = oh->_sysc_cache; | ||
| 905 | _set_clockactivity(oh, clockact, &v); | ||
| 906 | _write_sysconfig(v, oh); | ||
| 907 | mutex_unlock(&omap_hwmod_mutex); | ||
| 908 | |||
| 909 | return 0; | ||
| 910 | } | ||
| 911 | |||
| 912 | |||
| 913 | /** | ||
| 914 | * _setup - do initial configuration of omap_hwmod | 925 | * _setup - do initial configuration of omap_hwmod |
| 915 | * @oh: struct omap_hwmod * | 926 | * @oh: struct omap_hwmod * |
| 916 | * | 927 | * |
| @@ -948,11 +959,19 @@ static int _setup(struct omap_hwmod *oh) | |||
| 948 | 959 | ||
| 949 | _enable(oh); | 960 | _enable(oh); |
| 950 | 961 | ||
| 951 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) | 962 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) { |
| 952 | _reset(oh); | 963 | /* |
| 953 | 964 | * XXX Do the OCP_SYSCONFIG bits need to be | |
| 954 | /* XXX OCP AUTOIDLE bit? */ | 965 | * reprogrammed after a reset? If not, then this can |
| 955 | /* XXX OCP ENAWAKEUP bit? */ | 966 | * be removed. If they do, then probably the |
| 967 | * _enable() function should be split to avoid the | ||
| 968 | * rewrite of the OCP_SYSCONFIG register. | ||
| 969 | */ | ||
| 970 | if (oh->sysconfig) { | ||
| 971 | _update_sysc_cache(oh); | ||
| 972 | _sysc_enable(oh); | ||
| 973 | } | ||
| 974 | } | ||
| 956 | 975 | ||
| 957 | if (!(oh->flags & HWMOD_INIT_NO_IDLE)) | 976 | if (!(oh->flags & HWMOD_INIT_NO_IDLE)) |
| 958 | _idle(oh); | 977 | _idle(oh); |
| @@ -1348,8 +1367,9 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
| 1348 | /* For each IRQ, DMA, memory area, fill in array.*/ | 1367 | /* For each IRQ, DMA, memory area, fill in array.*/ |
| 1349 | 1368 | ||
| 1350 | for (i = 0; i < oh->mpu_irqs_cnt; i++) { | 1369 | for (i = 0; i < oh->mpu_irqs_cnt; i++) { |
| 1351 | (res + r)->start = *(oh->mpu_irqs + i); | 1370 | (res + r)->name = (oh->mpu_irqs + i)->name; |
| 1352 | (res + r)->end = *(oh->mpu_irqs + i); | 1371 | (res + r)->start = (oh->mpu_irqs + i)->irq; |
| 1372 | (res + r)->end = (oh->mpu_irqs + i)->irq; | ||
| 1353 | (res + r)->flags = IORESOURCE_IRQ; | 1373 | (res + r)->flags = IORESOURCE_IRQ; |
| 1354 | r++; | 1374 | r++; |
| 1355 | } | 1375 | } |
| @@ -1454,62 +1474,6 @@ int omap_hwmod_del_initiator_dep(struct omap_hwmod *oh, | |||
| 1454 | } | 1474 | } |
| 1455 | 1475 | ||
| 1456 | /** | 1476 | /** |
| 1457 | * omap_hwmod_set_clockact_none - set clockactivity test to BOTH | ||
| 1458 | * @oh: struct omap_hwmod * | ||
| 1459 | * | ||
| 1460 | * On some modules, this function can affect the wakeup latency vs. | ||
| 1461 | * power consumption balance. Intended to be called by the | ||
| 1462 | * omap_device layer. Passes along the return value from | ||
| 1463 | * _write_clockact_lock(). | ||
| 1464 | */ | ||
| 1465 | int omap_hwmod_set_clockact_both(struct omap_hwmod *oh) | ||
| 1466 | { | ||
| 1467 | return _write_clockact_lock(oh, CLOCKACT_TEST_BOTH); | ||
| 1468 | } | ||
| 1469 | |||
| 1470 | /** | ||
| 1471 | * omap_hwmod_set_clockact_none - set clockactivity test to MAIN | ||
| 1472 | * @oh: struct omap_hwmod * | ||
| 1473 | * | ||
| 1474 | * On some modules, this function can affect the wakeup latency vs. | ||
| 1475 | * power consumption balance. Intended to be called by the | ||
| 1476 | * omap_device layer. Passes along the return value from | ||
| 1477 | * _write_clockact_lock(). | ||
| 1478 | */ | ||
| 1479 | int omap_hwmod_set_clockact_main(struct omap_hwmod *oh) | ||
| 1480 | { | ||
| 1481 | return _write_clockact_lock(oh, CLOCKACT_TEST_MAIN); | ||
| 1482 | } | ||
| 1483 | |||
| 1484 | /** | ||
| 1485 | * omap_hwmod_set_clockact_none - set clockactivity test to ICLK | ||
| 1486 | * @oh: struct omap_hwmod * | ||
| 1487 | * | ||
| 1488 | * On some modules, this function can affect the wakeup latency vs. | ||
| 1489 | * power consumption balance. Intended to be called by the | ||
| 1490 | * omap_device layer. Passes along the return value from | ||
| 1491 | * _write_clockact_lock(). | ||
| 1492 | */ | ||
| 1493 | int omap_hwmod_set_clockact_iclk(struct omap_hwmod *oh) | ||
| 1494 | { | ||
| 1495 | return _write_clockact_lock(oh, CLOCKACT_TEST_ICLK); | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | /** | ||
| 1499 | * omap_hwmod_set_clockact_none - set clockactivity test to NONE | ||
| 1500 | * @oh: struct omap_hwmod * | ||
| 1501 | * | ||
| 1502 | * On some modules, this function can affect the wakeup latency vs. | ||
| 1503 | * power consumption balance. Intended to be called by the | ||
| 1504 | * omap_device layer. Passes along the return value from | ||
| 1505 | * _write_clockact_lock(). | ||
| 1506 | */ | ||
| 1507 | int omap_hwmod_set_clockact_none(struct omap_hwmod *oh) | ||
| 1508 | { | ||
| 1509 | return _write_clockact_lock(oh, CLOCKACT_TEST_NONE); | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | /** | ||
| 1513 | * omap_hwmod_enable_wakeup - allow device to wake up the system | 1477 | * omap_hwmod_enable_wakeup - allow device to wake up the system |
| 1514 | * @oh: struct omap_hwmod * | 1478 | * @oh: struct omap_hwmod * |
| 1515 | * | 1479 | * |
