Commit dc0555ded50f50e4967269e97877721c731c75fc

Authored by Suman Anna
1 parent 98604588b2

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);
drivers/iommu/omap-iommu.h
... ... @@ -60,6 +60,8 @@
60 60  
61 61 int has_bus_err_back;
62 62 u32 id;
  63 +
  64 + u8 pwrst;
63 65 };
64 66  
65 67 struct cr_regs {