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 | * |