rk29: work around CRU_CLKGATE3_CON bit21~20 & CRU_SOFTRST0_CON bit29~27 bug
author黄涛 <huangtao@rock-chips.com>
Fri, 11 Feb 2011 10:56:20 +0000 (18:56 +0800)
committer黄涛 <huangtao@rock-chips.com>
Fri, 11 Feb 2011 10:56:35 +0000 (18:56 +0800)
arch/arm/mach-rk29/clock.c
arch/arm/mach-rk29/include/mach/cru.h

index 2cf337024b7df0422192565505cb40be29693b02..3d5959da06df0be40d8a43a9234de66692a6ca0a 100755 (executable)
@@ -179,6 +179,9 @@ static int clksel_set_parent(struct clk *clk, struct clk *parent)
        return -EINVAL;
 }
 
+/* Work around CRU_CLKGATE3_CON bit21~20 bug */
+static volatile u32 cru_clkgate3_con_mirror;
+
 static int gate_mode(struct clk *clk, int on)
 {
        u32 reg;
@@ -192,17 +195,55 @@ static int gate_mode(struct clk *clk, int on)
        reg += (idx >> 5) << 2;
        idx &= 0x1F;
 
-       v = cru_readl(reg);
-       if (on) {
+       if (reg == CRU_CLKGATE3_CON)
+               v = cru_clkgate3_con_mirror;
+       else
+               v = cru_readl(reg);
+
+       if (on)
                v &= ~(1 << idx);       // clear bit 
-       } else {
+       else
                v |= (1 << idx);        // set bit
-       }
+
+       if (reg == CRU_CLKGATE3_CON)
+               cru_clkgate3_con_mirror = v;
        cru_writel(v, reg);
 
        return 0;
 }
 
+/* Work around CRU_SOFTRST0_CON bit29~27 bug */
+static volatile u32 cru_softrst0_con_mirror;
+
+void cru_set_soft_reset(enum cru_soft_reset idx, bool on)
+{
+       unsigned long flags;
+       u32 reg = CRU_SOFTRST0_CON + ((idx >> 5) << 2);
+       u32 mask = 1 << (idx & 31);
+       u32 v;
+
+       if (idx >= SOFT_RST_MAX)
+               return;
+
+       local_irq_save(flags);
+
+       if (reg == CRU_SOFTRST0_CON)
+               v = cru_softrst0_con_mirror;
+       else
+               v = cru_readl(reg);
+
+       if (on)
+               v |= mask;
+       else
+               v &= ~mask;
+
+       if (reg == CRU_SOFTRST0_CON)
+               cru_softrst0_con_mirror = v;
+       cru_writel(v, reg);
+
+       local_irq_restore(flags);
+}
+
 static struct clk xin24m = {
        .name           = "xin24m",
        .rate           = 24 * MHZ,
@@ -2259,6 +2300,9 @@ void __init rk29_clock_init(void)
 {
        struct clk_lookup *lk;
 
+       cru_clkgate3_con_mirror = cru_readl(CRU_CLKGATE3_CON);
+       cru_softrst0_con_mirror = cru_readl(CRU_SOFTRST0_CON);
+
        for (lk = clks; lk < clks + ARRAY_SIZE(clks); lk++)
                clk_preinit(lk->clk);
 
@@ -2311,7 +2355,10 @@ static void dump_clock(struct seq_file *s, struct clk *clk, int deep)
                reg += (idx >> 5) << 2;
                idx &= 0x1F;
 
-               v = cru_readl(reg) & (1 << idx);
+               if (reg == CRU_CLKGATE3_CON)
+                       v = cru_clkgate3_con_mirror & (1 << idx);
+               else
+                       v = cru_readl(reg) & (1 << idx);
                
                seq_printf(s, "%s ", v ? "off" : "on ");
        }
@@ -2409,6 +2456,11 @@ static int proc_clk_show(struct seq_file *s, void *v)
        seq_printf(s, "CLKGATE1 : 0x%08x\n", cru_readl(CRU_CLKGATE1_CON));
        seq_printf(s, "CLKGATE2 : 0x%08x\n", cru_readl(CRU_CLKGATE2_CON));
        seq_printf(s, "CLKGATE3 : 0x%08x\n", cru_readl(CRU_CLKGATE3_CON));
+       seq_printf(s, "CLKGATE3M: 0x%08x\n", cru_clkgate3_con_mirror);
+       seq_printf(s, "SOFTRST0 : 0x%08x\n", cru_readl(CRU_SOFTRST0_CON));
+       seq_printf(s, "SOFTRST0M: 0x%08x\n", cru_softrst0_con_mirror);
+       seq_printf(s, "SOFTRST1 : 0x%08x\n", cru_readl(CRU_SOFTRST1_CON));
+       seq_printf(s, "SOFTRST2 : 0x%08x\n", cru_readl(CRU_SOFTRST2_CON));
 
        seq_printf(s, "\nPMU Registers:\n");
        seq_printf(s, "WAKEUP_EN0 : 0x%08x\n", pmu_readl(PMU_WAKEUP_EN0));
index 27a0a8e76a1aa4f63a8150b92bd67b71cca20404..b6602e9ea9d9781ba914677351a919d52f1643ce 100644 (file)
@@ -296,24 +296,6 @@ enum cru_soft_reset {
 #define CRU_SOFTRST1_CON       0x70
 #define CRU_SOFTRST2_CON       0x74
 
-static inline void cru_set_soft_reset(enum cru_soft_reset idx, bool on)
-{
-       unsigned long flags;
-       u32 addr = RK29_CRU_BASE + CRU_SOFTRST0_CON + ((idx >> 5) << 2);
-       u32 mask = 1 << (idx & 31);
-       u32 v;
-
-       if (idx >= SOFT_RST_MAX)
-               return;
-
-       local_irq_save(flags);
-       v = readl(addr);
-       if (on)
-               v |= mask;
-       else
-               v &= ~mask;
-       writel(v, addr);
-       local_irq_restore(flags);
-}
+void cru_set_soft_reset(enum cru_soft_reset idx, bool on);
 
 #endif