diff options
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 69 |
1 files changed, 46 insertions, 23 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 4997c1a8b59d..5b07ad0251d7 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * omap_hwmod implementation for OMAP2/3/4 | 2 | * omap_hwmod implementation for OMAP2/3/4 |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2011 Nokia Corporation | 4 | * Copyright (C) 2009-2011 Nokia Corporation |
5 | * Copyright (C) 2011 Texas Instruments, Inc. | 5 | * Copyright (C) 2011-2012 Texas Instruments, Inc. |
6 | * | 6 | * |
7 | * Paul Walmsley, Benoît Cousson, Kevin Hilman | 7 | * Paul Walmsley, Benoît Cousson, Kevin Hilman |
8 | * | 8 | * |
@@ -1382,9 +1382,9 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name) | |||
1382 | * @oh: struct omap_hwmod * | 1382 | * @oh: struct omap_hwmod * |
1383 | * | 1383 | * |
1384 | * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be | 1384 | * Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be |
1385 | * enabled for this to work. Returns -EINVAL if the hwmod cannot be | 1385 | * enabled for this to work. Returns -ENOENT if the hwmod cannot be |
1386 | * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if | 1386 | * reset this way, -EINVAL if the hwmod is in the wrong state, |
1387 | * the module did not reset in time, or 0 upon success. | 1387 | * -ETIMEDOUT if the module did not reset in time, or 0 upon success. |
1388 | * | 1388 | * |
1389 | * In OMAP3 a specific SYSSTATUS register is used to get the reset status. | 1389 | * In OMAP3 a specific SYSSTATUS register is used to get the reset status. |
1390 | * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead | 1390 | * Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead |
@@ -1401,7 +1401,7 @@ static int _ocp_softreset(struct omap_hwmod *oh) | |||
1401 | 1401 | ||
1402 | if (!oh->class->sysc || | 1402 | if (!oh->class->sysc || |
1403 | !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) | 1403 | !(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET)) |
1404 | return -EINVAL; | 1404 | return -ENOENT; |
1405 | 1405 | ||
1406 | /* clocks must be on for this operation */ | 1406 | /* clocks must be on for this operation */ |
1407 | if (oh->_state != _HWMOD_STATE_ENABLED) { | 1407 | if (oh->_state != _HWMOD_STATE_ENABLED) { |
@@ -1462,37 +1462,60 @@ dis_opt_clks: | |||
1462 | * _reset - reset an omap_hwmod | 1462 | * _reset - reset an omap_hwmod |
1463 | * @oh: struct omap_hwmod * | 1463 | * @oh: struct omap_hwmod * |
1464 | * | 1464 | * |
1465 | * Resets an omap_hwmod @oh. The default software reset mechanism for | 1465 | * Resets an omap_hwmod @oh. If the module has a custom reset |
1466 | * most OMAP IP blocks is triggered via the OCP_SYSCONFIG.SOFTRESET | 1466 | * function pointer defined, then call it to reset the IP block, and |
1467 | * bit. However, some hwmods cannot be reset via this method: some | 1467 | * pass along its return value to the caller. Otherwise, if the IP |
1468 | * are not targets and therefore have no OCP header registers to | 1468 | * block has an OCP_SYSCONFIG register with a SOFTRESET bitfield |
1469 | * access; others (like the IVA) have idiosyncratic reset sequences. | 1469 | * associated with it, call a function to reset the IP block via that |
1470 | * So for these relatively rare cases, custom reset code can be | 1470 | * method, and pass along the return value to the caller. Finally, if |
1471 | * supplied in the struct omap_hwmod_class .reset function pointer. | 1471 | * the IP block has some hardreset lines associated with it, assert |
1472 | * Passes along the return value from either _reset() or the custom | 1472 | * all of those, but do _not_ deassert them. (This is because driver |
1473 | * reset function - these must return -EINVAL if the hwmod cannot be | 1473 | * authors have expressed an apparent requirement to control the |
1474 | * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if | 1474 | * deassertion of the hardreset lines themselves.) |
1475 | * the module did not reset in time, or 0 upon success. | 1475 | * |
1476 | * The default software reset mechanism for most OMAP IP blocks is | ||
1477 | * triggered via the OCP_SYSCONFIG.SOFTRESET bit. However, some | ||
1478 | * hwmods cannot be reset via this method. Some are not targets and | ||
1479 | * therefore have no OCP header registers to access. Others (like the | ||
1480 | * IVA) have idiosyncratic reset sequences. So for these relatively | ||
1481 | * rare cases, custom reset code can be supplied in the struct | ||
1482 | * omap_hwmod_class .reset function pointer. Passes along the return | ||
1483 | * value from either _ocp_softreset() or the custom reset function - | ||
1484 | * these must return -EINVAL if the hwmod cannot be reset this way or | ||
1485 | * if the hwmod is in the wrong state, -ETIMEDOUT if the module did | ||
1486 | * not reset in time, or 0 upon success. | ||
1476 | */ | 1487 | */ |
1477 | static int _reset(struct omap_hwmod *oh) | 1488 | static int _reset(struct omap_hwmod *oh) |
1478 | { | 1489 | { |
1479 | int ret; | 1490 | int i, r; |
1480 | 1491 | ||
1481 | pr_debug("omap_hwmod: %s: resetting\n", oh->name); | 1492 | pr_debug("omap_hwmod: %s: resetting\n", oh->name); |
1482 | 1493 | ||
1494 | if (oh->class->reset) { | ||
1495 | r = oh->class->reset(oh); | ||
1496 | } else { | ||
1497 | if (oh->rst_lines_cnt > 0) { | ||
1498 | for (i = 0; i < oh->rst_lines_cnt; i++) | ||
1499 | _assert_hardreset(oh, oh->rst_lines[i].name); | ||
1500 | return 0; | ||
1501 | } else { | ||
1502 | r = _ocp_softreset(oh); | ||
1503 | if (r == -ENOENT) | ||
1504 | r = 0; | ||
1505 | } | ||
1506 | } | ||
1507 | |||
1483 | /* | 1508 | /* |
1484 | * XXX We're not resetting modules with hardreset lines | 1509 | * OCP_SYSCONFIG bits need to be reprogrammed after a |
1485 | * automatically here. Should we do this also, or just expect | 1510 | * softreset. The _enable() function should be split to avoid |
1486 | * those modules to define custom reset functions? | 1511 | * the rewrite of the OCP_SYSCONFIG register. |
1487 | */ | 1512 | */ |
1488 | ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh); | ||
1489 | |||
1490 | if (oh->class->sysc) { | 1513 | if (oh->class->sysc) { |
1491 | _update_sysc_cache(oh); | 1514 | _update_sysc_cache(oh); |
1492 | _enable_sysc(oh); | 1515 | _enable_sysc(oh); |
1493 | } | 1516 | } |
1494 | 1517 | ||
1495 | return ret; | 1518 | return r; |
1496 | } | 1519 | } |
1497 | 1520 | ||
1498 | /** | 1521 | /** |