diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 154 |
1 files changed, 100 insertions, 54 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 9e89a58711b..f76f133780c 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * omap_hwmod implementation for OMAP2/3/4 | 2 | * omap_hwmod implementation for OMAP2/3/4 |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2010 Nokia Corporation | 4 | * Copyright (C) 2009-2011 Nokia Corporation |
5 | * | 5 | * |
6 | * Paul Walmsley, Benoît Cousson, Kevin Hilman | 6 | * Paul Walmsley, Benoît Cousson, Kevin Hilman |
7 | * | 7 | * |
@@ -162,9 +162,6 @@ static LIST_HEAD(omap_hwmod_list); | |||
162 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ | 162 | /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ |
163 | static struct omap_hwmod *mpu_oh; | 163 | static struct omap_hwmod *mpu_oh; |
164 | 164 | ||
165 | /* inited: 0 if omap_hwmod_init() has not yet been called; 1 otherwise */ | ||
166 | static u8 inited; | ||
167 | |||
168 | 165 | ||
169 | /* Private functions */ | 166 | /* Private functions */ |
170 | 167 | ||
@@ -904,18 +901,16 @@ static struct omap_hwmod *_lookup(const char *name) | |||
904 | * @oh: struct omap_hwmod * | 901 | * @oh: struct omap_hwmod * |
905 | * @data: not used; pass NULL | 902 | * @data: not used; pass NULL |
906 | * | 903 | * |
907 | * Called by omap_hwmod_late_init() (after omap2_clk_init()). | 904 | * Called by omap_hwmod_setup_*() (after omap2_clk_init()). |
908 | * Resolves all clock names embedded in the hwmod. Returns -EINVAL if | 905 | * Resolves all clock names embedded in the hwmod. Returns 0 on |
909 | * the omap_hwmod has not yet been registered or if the clocks have | 906 | * success, or a negative error code on failure. |
910 | * already been initialized, 0 on success, or a non-zero error on | ||
911 | * failure. | ||
912 | */ | 907 | */ |
913 | static int _init_clocks(struct omap_hwmod *oh, void *data) | 908 | static int _init_clocks(struct omap_hwmod *oh, void *data) |
914 | { | 909 | { |
915 | int ret = 0; | 910 | int ret = 0; |
916 | 911 | ||
917 | if (!oh || (oh->_state != _HWMOD_STATE_REGISTERED)) | 912 | if (oh->_state != _HWMOD_STATE_REGISTERED) |
918 | return -EINVAL; | 913 | return 0; |
919 | 914 | ||
920 | pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name); | 915 | pr_debug("omap_hwmod: %s: looking up clocks\n", oh->name); |
921 | 916 | ||
@@ -1354,14 +1349,16 @@ static int _shutdown(struct omap_hwmod *oh) | |||
1354 | * @oh: struct omap_hwmod * | 1349 | * @oh: struct omap_hwmod * |
1355 | * | 1350 | * |
1356 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh | 1351 | * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh |
1357 | * OCP_SYSCONFIG register. Returns -EINVAL if the hwmod is in the | 1352 | * OCP_SYSCONFIG register. Returns 0. |
1358 | * wrong state or returns 0. | ||
1359 | */ | 1353 | */ |
1360 | static int _setup(struct omap_hwmod *oh, void *data) | 1354 | static int _setup(struct omap_hwmod *oh, void *data) |
1361 | { | 1355 | { |
1362 | int i, r; | 1356 | int i, r; |
1363 | u8 postsetup_state; | 1357 | u8 postsetup_state; |
1364 | 1358 | ||
1359 | if (oh->_state != _HWMOD_STATE_CLKS_INITED) | ||
1360 | return 0; | ||
1361 | |||
1365 | /* Set iclk autoidle mode */ | 1362 | /* Set iclk autoidle mode */ |
1366 | if (oh->slaves_cnt > 0) { | 1363 | if (oh->slaves_cnt > 0) { |
1367 | for (i = 0; i < oh->slaves_cnt; i++) { | 1364 | for (i = 0; i < oh->slaves_cnt; i++) { |
@@ -1455,7 +1452,7 @@ static int _setup(struct omap_hwmod *oh, void *data) | |||
1455 | */ | 1452 | */ |
1456 | static int __init _register(struct omap_hwmod *oh) | 1453 | static int __init _register(struct omap_hwmod *oh) |
1457 | { | 1454 | { |
1458 | int ret, ms_id; | 1455 | int ms_id; |
1459 | 1456 | ||
1460 | if (!oh || !oh->name || !oh->class || !oh->class->name || | 1457 | if (!oh || !oh->name || !oh->class || !oh->class->name || |
1461 | (oh->_state != _HWMOD_STATE_UNKNOWN)) | 1458 | (oh->_state != _HWMOD_STATE_UNKNOWN)) |
@@ -1478,9 +1475,14 @@ static int __init _register(struct omap_hwmod *oh) | |||
1478 | 1475 | ||
1479 | oh->_state = _HWMOD_STATE_REGISTERED; | 1476 | oh->_state = _HWMOD_STATE_REGISTERED; |
1480 | 1477 | ||
1481 | ret = 0; | 1478 | /* |
1479 | * XXX Rather than doing a strcmp(), this should test a flag | ||
1480 | * set in the hwmod data, inserted by the autogenerator code. | ||
1481 | */ | ||
1482 | if (!strcmp(oh->name, MPU_INITIATOR_NAME)) | ||
1483 | mpu_oh = oh; | ||
1482 | 1484 | ||
1483 | return ret; | 1485 | return 0; |
1484 | } | 1486 | } |
1485 | 1487 | ||
1486 | 1488 | ||
@@ -1583,38 +1585,30 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data), | |||
1583 | return ret; | 1585 | return ret; |
1584 | } | 1586 | } |
1585 | 1587 | ||
1586 | |||
1587 | /** | 1588 | /** |
1588 | * omap_hwmod_init - init omap_hwmod code and register hwmods | 1589 | * omap_hwmod_register - register an array of hwmods |
1589 | * @ohs: pointer to an array of omap_hwmods to register | 1590 | * @ohs: pointer to an array of omap_hwmods to register |
1590 | * | 1591 | * |
1591 | * Intended to be called early in boot before the clock framework is | 1592 | * Intended to be called early in boot before the clock framework is |
1592 | * initialized. If @ohs is not null, will register all omap_hwmods | 1593 | * initialized. If @ohs is not null, will register all omap_hwmods |
1593 | * listed in @ohs that are valid for this chip. Returns -EINVAL if | 1594 | * listed in @ohs that are valid for this chip. Returns 0. |
1594 | * omap_hwmod_init() has already been called or 0 otherwise. | ||
1595 | */ | 1595 | */ |
1596 | int __init omap_hwmod_init(struct omap_hwmod **ohs) | 1596 | int __init omap_hwmod_register(struct omap_hwmod **ohs) |
1597 | { | 1597 | { |
1598 | struct omap_hwmod *oh; | 1598 | int r, i; |
1599 | int r; | ||
1600 | |||
1601 | if (inited) | ||
1602 | return -EINVAL; | ||
1603 | |||
1604 | inited = 1; | ||
1605 | 1599 | ||
1606 | if (!ohs) | 1600 | if (!ohs) |
1607 | return 0; | 1601 | return 0; |
1608 | 1602 | ||
1609 | oh = *ohs; | 1603 | i = 0; |
1610 | while (oh) { | 1604 | do { |
1611 | if (omap_chip_is(oh->omap_chip)) { | 1605 | if (!omap_chip_is(ohs[i]->omap_chip)) |
1612 | r = _register(oh); | 1606 | continue; |
1613 | WARN(r, "omap_hwmod: %s: _register returned " | 1607 | |
1614 | "%d\n", oh->name, r); | 1608 | r = _register(ohs[i]); |
1615 | } | 1609 | WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name, |
1616 | oh = *++ohs; | 1610 | r); |
1617 | } | 1611 | } while (ohs[++i]); |
1618 | 1612 | ||
1619 | return 0; | 1613 | return 0; |
1620 | } | 1614 | } |
@@ -1622,12 +1616,14 @@ int __init omap_hwmod_init(struct omap_hwmod **ohs) | |||
1622 | /* | 1616 | /* |
1623 | * _populate_mpu_rt_base - populate the virtual address for a hwmod | 1617 | * _populate_mpu_rt_base - populate the virtual address for a hwmod |
1624 | * | 1618 | * |
1625 | * Must be called only from omap_hwmod_late_init so ioremap works properly. | 1619 | * Must be called only from omap_hwmod_setup_*() so ioremap works properly. |
1626 | * Assumes the caller takes care of locking if needed. | 1620 | * Assumes the caller takes care of locking if needed. |
1627 | * | ||
1628 | */ | 1621 | */ |
1629 | static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data) | 1622 | static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data) |
1630 | { | 1623 | { |
1624 | if (oh->_state != _HWMOD_STATE_REGISTERED) | ||
1625 | return 0; | ||
1626 | |||
1631 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | 1627 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) |
1632 | return 0; | 1628 | return 0; |
1633 | 1629 | ||
@@ -1640,31 +1636,81 @@ static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data) | |||
1640 | } | 1636 | } |
1641 | 1637 | ||
1642 | /** | 1638 | /** |
1643 | * omap_hwmod_late_init - do some post-clock framework initialization | 1639 | * omap_hwmod_setup_one - set up a single hwmod |
1640 | * @oh_name: const char * name of the already-registered hwmod to set up | ||
1641 | * | ||
1642 | * Must be called after omap2_clk_init(). Resolves the struct clk | ||
1643 | * names to struct clk pointers for each registered omap_hwmod. Also | ||
1644 | * calls _setup() on each hwmod. Returns -EINVAL upon error or 0 upon | ||
1645 | * success. | ||
1646 | */ | ||
1647 | int __init omap_hwmod_setup_one(const char *oh_name) | ||
1648 | { | ||
1649 | struct omap_hwmod *oh; | ||
1650 | int r; | ||
1651 | |||
1652 | pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__); | ||
1653 | |||
1654 | if (!mpu_oh) { | ||
1655 | pr_err("omap_hwmod: %s: cannot setup_one: MPU initiator hwmod %s not yet registered\n", | ||
1656 | oh_name, MPU_INITIATOR_NAME); | ||
1657 | return -EINVAL; | ||
1658 | } | ||
1659 | |||
1660 | oh = _lookup(oh_name); | ||
1661 | if (!oh) { | ||
1662 | WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name); | ||
1663 | return -EINVAL; | ||
1664 | } | ||
1665 | |||
1666 | if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh) | ||
1667 | omap_hwmod_setup_one(MPU_INITIATOR_NAME); | ||
1668 | |||
1669 | r = _populate_mpu_rt_base(oh, NULL); | ||
1670 | if (IS_ERR_VALUE(r)) { | ||
1671 | WARN(1, "omap_hwmod: %s: couldn't set mpu_rt_base\n", oh_name); | ||
1672 | return -EINVAL; | ||
1673 | } | ||
1674 | |||
1675 | r = _init_clocks(oh, NULL); | ||
1676 | if (IS_ERR_VALUE(r)) { | ||
1677 | WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh_name); | ||
1678 | return -EINVAL; | ||
1679 | } | ||
1680 | |||
1681 | _setup(oh, NULL); | ||
1682 | |||
1683 | return 0; | ||
1684 | } | ||
1685 | |||
1686 | /** | ||
1687 | * omap_hwmod_setup - do some post-clock framework initialization | ||
1644 | * | 1688 | * |
1645 | * Must be called after omap2_clk_init(). Resolves the struct clk names | 1689 | * Must be called after omap2_clk_init(). Resolves the struct clk names |
1646 | * to struct clk pointers for each registered omap_hwmod. Also calls | 1690 | * to struct clk pointers for each registered omap_hwmod. Also calls |
1647 | * _setup() on each hwmod. Returns 0. | 1691 | * _setup() on each hwmod. Returns 0 upon success. |
1648 | */ | 1692 | */ |
1649 | static int __init omap_hwmod_late_init(void) | 1693 | static int __init omap_hwmod_setup_all(void) |
1650 | { | 1694 | { |
1651 | int r; | 1695 | int r; |
1652 | 1696 | ||
1697 | if (!mpu_oh) { | ||
1698 | pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n", | ||
1699 | __func__, MPU_INITIATOR_NAME); | ||
1700 | return -EINVAL; | ||
1701 | } | ||
1702 | |||
1653 | r = omap_hwmod_for_each(_populate_mpu_rt_base, NULL); | 1703 | r = omap_hwmod_for_each(_populate_mpu_rt_base, NULL); |
1654 | 1704 | ||
1655 | /* XXX check return value */ | ||
1656 | r = omap_hwmod_for_each(_init_clocks, NULL); | 1705 | r = omap_hwmod_for_each(_init_clocks, NULL); |
1657 | WARN(r, "omap_hwmod: omap_hwmod_late_init(): _init_clocks failed\n"); | 1706 | WARN(IS_ERR_VALUE(r), |
1658 | 1707 | "omap_hwmod: %s: _init_clocks failed\n", __func__); | |
1659 | mpu_oh = omap_hwmod_lookup(MPU_INITIATOR_NAME); | ||
1660 | WARN(!mpu_oh, "omap_hwmod: could not find MPU initiator hwmod %s\n", | ||
1661 | MPU_INITIATOR_NAME); | ||
1662 | 1708 | ||
1663 | omap_hwmod_for_each(_setup, NULL); | 1709 | omap_hwmod_for_each(_setup, NULL); |
1664 | 1710 | ||
1665 | return 0; | 1711 | return 0; |
1666 | } | 1712 | } |
1667 | core_initcall(omap_hwmod_late_init); | 1713 | core_initcall(omap_hwmod_setup_all); |
1668 | 1714 | ||
1669 | /** | 1715 | /** |
1670 | * omap_hwmod_enable - enable an omap_hwmod | 1716 | * omap_hwmod_enable - enable an omap_hwmod |
@@ -2183,11 +2229,11 @@ int omap_hwmod_for_each_by_class(const char *classname, | |||
2183 | * @oh: struct omap_hwmod * | 2229 | * @oh: struct omap_hwmod * |
2184 | * @state: state that _setup() should leave the hwmod in | 2230 | * @state: state that _setup() should leave the hwmod in |
2185 | * | 2231 | * |
2186 | * Sets the hwmod state that @oh will enter at the end of _setup() (called by | 2232 | * Sets the hwmod state that @oh will enter at the end of _setup() |
2187 | * omap_hwmod_late_init()). Only valid to call between calls to | 2233 | * (called by omap_hwmod_setup_*()). Only valid to call between |
2188 | * omap_hwmod_init() and omap_hwmod_late_init(). Returns 0 upon success or | 2234 | * calling omap_hwmod_register() and omap_hwmod_setup_*(). Returns |
2189 | * -EINVAL if there is a problem with the arguments or if the hwmod is | 2235 | * 0 upon success or -EINVAL if there is a problem with the arguments |
2190 | * in the wrong state. | 2236 | * or if the hwmod is in the wrong state. |
2191 | */ | 2237 | */ |
2192 | int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) | 2238 | int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state) |
2193 | { | 2239 | { |