Commit dc0555ded50f50e4967269e97877721c731c75fc
1 parent
98604588b2
Exists in
smarc-ti-linux-3.14.y
and in
1 other branch
iommu/omap: fix boot issue on remoteprocs with AMMU/Unicache
This patch invokes the .set_pwrdm_constraint pdata ops, if present, during the runtime resume and suspend callbacks to resolve a possible boot issue on remote processors with AMMU/Unicache, and whose power domains enter RET between the time the MMU is powered ON to the time the remote processor is released from reset. The issue is described in detail in [1]. The pdata ops implementation restricts the target power domain to ON during resume, and back to the original power domain state during suspend, and thereby eliminating the conditions for the boot issue. The implementation is effective only when the original power domain state is either RET or OFF, and is a no-op when it is ON or INACTIVE. Doing this in the PM runtime callbacks ensures that the target power domain stays ON only during the time when the remote processor is active. The remote processors are typically auto-suspended after an inactivity period of 10 seconds. The .set_pwrdm_constraint ops need to be plugged in pdata-quirks for the affected remote processors to be able to boot properly. [1] http://git.ti.com/gitweb/?p=rpmsg/rpmsg.git;a=commit;h=6d6dd44c55638d54a151bf2ae6cc77b2f4e459d0 Signed-off-by: Suman Anna <s-anna@ti.com>
Showing 3 changed files with 49 additions and 0 deletions Side-by-side Diff
arch/arm/mach-omap2/omap-iommu.c
... | ... | @@ -20,6 +20,36 @@ |
20 | 20 | #include "soc.h" |
21 | 21 | #include "omap_hwmod.h" |
22 | 22 | #include "omap_device.h" |
23 | +#include "powerdomain.h" | |
24 | + | |
25 | +int omap_iommu_set_pwrdm_constraint(struct platform_device *pdev, bool request, | |
26 | + u8 *pwrst) | |
27 | +{ | |
28 | + struct powerdomain *pwrdm; | |
29 | + struct omap_device *od; | |
30 | + u8 next_pwrst; | |
31 | + | |
32 | + od = to_omap_device(pdev); | |
33 | + if (!od) | |
34 | + return -ENODEV; | |
35 | + | |
36 | + if (od->hwmods_cnt != 1) | |
37 | + return -EINVAL; | |
38 | + | |
39 | + pwrdm = omap_hwmod_get_pwrdm(od->hwmods[0]); | |
40 | + if (!pwrdm) | |
41 | + return -EINVAL; | |
42 | + | |
43 | + if (request) | |
44 | + *pwrst = pwrdm_read_next_pwrst(pwrdm); | |
45 | + | |
46 | + if (*pwrst > PWRDM_POWER_RET) | |
47 | + return 0; | |
48 | + | |
49 | + next_pwrst = request ? PWRDM_POWER_ON : *pwrst; | |
50 | + | |
51 | + return pwrdm_set_next_pwrst(pwrdm, next_pwrst); | |
52 | +} | |
23 | 53 | |
24 | 54 | static int __init omap_iommu_dev_init(struct omap_hwmod *oh, void *unused) |
25 | 55 | { |
drivers/iommu/omap-iommu.c
... | ... | @@ -1045,6 +1045,7 @@ |
1045 | 1045 | struct platform_device *pdev = to_platform_device(dev); |
1046 | 1046 | struct iommu_platform_data *pdata = dev_get_platdata(dev); |
1047 | 1047 | struct omap_iommu *obj = to_iommu(dev); |
1048 | + int ret; | |
1048 | 1049 | |
1049 | 1050 | /* save the TLBs only during suspend, and not for power down */ |
1050 | 1051 | if (obj->domain && obj->iopgd) |
... | ... | @@ -1059,6 +1060,14 @@ |
1059 | 1060 | if (pdata && pdata->assert_reset) |
1060 | 1061 | pdata->assert_reset(pdev, pdata->reset_name); |
1061 | 1062 | |
1063 | + if (pdata && pdata->set_pwrdm_constraint) { | |
1064 | + ret = pdata->set_pwrdm_constraint(pdev, false, &obj->pwrst); | |
1065 | + if (ret) { | |
1066 | + dev_warn(dev, "pwrdm_constraint failed to be reset, status = %d\n", | |
1067 | + ret); | |
1068 | + } | |
1069 | + } | |
1070 | + | |
1062 | 1071 | return 0; |
1063 | 1072 | } |
1064 | 1073 | |
... | ... | @@ -1080,6 +1089,14 @@ |
1080 | 1089 | struct iommu_platform_data *pdata = dev_get_platdata(dev); |
1081 | 1090 | struct omap_iommu *obj = to_iommu(dev); |
1082 | 1091 | int ret = 0; |
1092 | + | |
1093 | + if (pdata && pdata->set_pwrdm_constraint) { | |
1094 | + ret = pdata->set_pwrdm_constraint(pdev, true, &obj->pwrst); | |
1095 | + if (ret) { | |
1096 | + dev_warn(dev, "pwrdm_constraint failed to be set, status = %d\n", | |
1097 | + ret); | |
1098 | + } | |
1099 | + } | |
1083 | 1100 | |
1084 | 1101 | if (pdata && pdata->deassert_reset) { |
1085 | 1102 | ret = pdata->deassert_reset(pdev, pdata->reset_name); |