rk30: pmu: support idle request
author黄涛 <huangtao@rock-chips.com>
Wed, 21 Mar 2012 11:15:36 +0000 (19:15 +0800)
committer黄涛 <huangtao@rock-chips.com>
Wed, 21 Mar 2012 11:20:36 +0000 (19:20 +0800)
arch/arm/mach-rk30/include/mach/pmu.h
arch/arm/mach-rk30/pmu.c

index 51b2a7d03b06277e2bb7b143779ee50a40ef560b..8433d79fd196fbb034655b94418d0f1f0bf345cb 100644 (file)
@@ -34,6 +34,7 @@ enum pmu_power_domain {
        PD_PERI = 6,
        PD_VIO,
        PD_VIDEO,
+       PD_VCODEC = PD_VIDEO,
        PD_GPU,
        PD_DBG,
 };
@@ -45,4 +46,14 @@ static inline bool pmu_power_domain_is_on(enum pmu_power_domain pd)
 
 void pmu_set_power_domain(enum pmu_power_domain pd, bool on);
 
+enum pmu_idle_req {
+       IDLE_REQ_CPU = 0,
+       IDLE_REQ_PERI,
+       IDLE_REQ_GPU,
+       IDLE_REQ_VIDEO,
+       IDLE_REQ_VIO,
+};
+
+void pmu_set_idle_request(enum pmu_idle_req req, bool idle);
+
 #endif
index ec26036dba3a77793054a9044ff4bd50a8751b3f..7a244318c852ed557a46335429e02e0cf391f73f 100644 (file)
@@ -39,6 +39,48 @@ void pmu_set_power_domain(enum pmu_power_domain pd, bool on)
        unsigned long flags;
 
        spin_lock_irqsave(&pmu_pd_lock, flags);
+       if (!on) {
+               /* if power down, idle request to NIU first */
+               if (pd == PD_VIO)
+                       pmu_set_idle_request(IDLE_REQ_VIO, true);
+               else if (pd == PD_VIDEO)
+                       pmu_set_idle_request(IDLE_REQ_VIDEO, true);
+               else if (pd == PD_GPU)
+                       pmu_set_idle_request(IDLE_REQ_GPU, true);
+       }
        do_pmu_set_power_domain(pd, on);
+       if (on) {
+               /* if power up, idle request release to NIU */
+               if (pd == PD_VIO)
+                       pmu_set_idle_request(IDLE_REQ_VIO, false);
+               else if (pd == PD_VIDEO)
+                       pmu_set_idle_request(IDLE_REQ_VIDEO, false);
+               else if (pd == PD_GPU)
+                       pmu_set_idle_request(IDLE_REQ_GPU, false);
+       }
        spin_unlock_irqrestore(&pmu_pd_lock, flags);
 }
+
+static DEFINE_SPINLOCK(pmu_misc_con1_lock);
+
+void pmu_set_idle_request(enum pmu_idle_req req, bool idle)
+{
+       u32 idle_mask = 1 << (26 - req);
+       u32 idle_target = idle << (26 - req);
+       u32 mask = 1 << (req + 1);
+       u32 val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pmu_misc_con1_lock, flags);
+       val = readl_relaxed(RK30_PMU_BASE + PMU_MISC_CON1);
+       if (idle)
+               val |=  mask;
+       else
+               val &= ~mask;
+       writel_relaxed(val, RK30_PMU_BASE + PMU_MISC_CON1);
+       dsb();
+
+       while ((readl_relaxed(RK30_PMU_BASE + PMU_PWRDN_ST) & idle_mask) != idle_target)
+               ;
+       spin_unlock_irqrestore(&pmu_misc_con1_lock, flags);
+}