Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vss.c
Go to the documentation of this file.
1 /*
2  * Au1300 media block power gating (VSS)
3  *
4  * This is a stop-gap solution until I have the clock framework integration
5  * ready. This stuff here really must be handled transparently when clocks
6  * for various media blocks are enabled/disabled.
7  */
8 
9 #include <linux/module.h>
10 #include <linux/spinlock.h>
11 #include <asm/mach-au1x00/au1000.h>
12 
13 #define VSS_GATE 0x00 /* gate wait timers */
14 #define VSS_CLKRST 0x04 /* clock/block control */
15 #define VSS_FTR 0x08 /* footers */
16 
17 #define VSS_ADDR(blk) (KSEG1ADDR(AU1300_VSS_PHYS_ADDR) + (blk * 0x0c))
18 
19 static DEFINE_SPINLOCK(au1300_vss_lock);
20 
21 /* enable a block as outlined in the databook */
22 static inline void __enable_block(int block)
23 {
24  void __iomem *base = (void __iomem *)VSS_ADDR(block);
25 
26  __raw_writel(3, base + VSS_CLKRST); /* enable clock, assert reset */
27  wmb();
28 
29  __raw_writel(0x01fffffe, base + VSS_GATE); /* maximum setup time */
30  wmb();
31 
32  /* enable footers in sequence */
33  __raw_writel(0x01, base + VSS_FTR);
34  wmb();
35  __raw_writel(0x03, base + VSS_FTR);
36  wmb();
37  __raw_writel(0x07, base + VSS_FTR);
38  wmb();
39  __raw_writel(0x0f, base + VSS_FTR);
40  wmb();
41 
42  __raw_writel(0x01ffffff, base + VSS_GATE); /* start FSM too */
43  wmb();
44 
45  __raw_writel(2, base + VSS_CLKRST); /* deassert reset */
46  wmb();
47 
48  __raw_writel(0x1f, base + VSS_FTR); /* enable isolation cells */
49  wmb();
50 }
51 
52 /* disable a block as outlined in the databook */
53 static inline void __disable_block(int block)
54 {
55  void __iomem *base = (void __iomem *)VSS_ADDR(block);
56 
57  __raw_writel(0x0f, base + VSS_FTR); /* disable isolation cells */
58  wmb();
59  __raw_writel(0, base + VSS_GATE); /* disable FSM */
60  wmb();
61  __raw_writel(3, base + VSS_CLKRST); /* assert reset */
62  wmb();
63  __raw_writel(1, base + VSS_CLKRST); /* disable clock */
64  wmb();
65  __raw_writel(0, base + VSS_FTR); /* disable all footers */
66  wmb();
67 }
68 
69 void au1300_vss_block_control(int block, int enable)
70 {
71  unsigned long flags;
72 
73  if (alchemy_get_cputype() != ALCHEMY_CPU_AU1300)
74  return;
75 
76  /* only one block at a time */
77  spin_lock_irqsave(&au1300_vss_lock, flags);
78  if (enable)
79  __enable_block(block);
80  else
81  __disable_block(block);
82  spin_unlock_irqrestore(&au1300_vss_lock, flags);
83 }