summaryrefslogtreecommitdiffstats
path: root/arch/mips/alchemy/common/vss.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-01-14 13:05:21 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-14 13:05:21 -0800
commit4964e0664c80680fa6b28ef91381c076a5b25c2c (patch)
tree62099c5aaeee7274bcc66bcfba35d479affa97cf /arch/mips/alchemy/common/vss.c
parent0a80939b3e6af4b0dc93bf88ec02fd7e90a16f1b (diff)
parent7bf6612e8a9d6a0b3b82e8e2611942be1258b307 (diff)
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (119 commits) MIPS: Delete unused function add_temporary_entry. MIPS: Set default pci cache line size. MIPS: Flush huge TLB MIPS: Octeon: Remove SYS_SUPPORTS_HIGHMEM. MIPS: Octeon: Add support for OCTEON II PCIe MIPS: Octeon: Update PCI Latency timer and enable more error reporting. MIPS: Alchemy: Update cpu-feature-overrides MIPS: Alchemy: db1200: Improve PB1200 detection. MIPS: Alchemy: merge Au1000 and Au1300-style IRQ controller code. MIPS: Alchemy: chain IRQ controllers to MIPS IRQ controller MIPS: Alchemy: irq: register pm at irq init time MIPS: Alchemy: Touchscreen support on DB1100 MIPS: Alchemy: Hook up IrDA on DB1000/DB1100 net/irda: convert au1k_ir to platform driver. MIPS: Alchemy: remove unused board headers MTD: nand: make au1550nd.c a platform_driver MIPS: Netlogic: Mark Netlogic chips as SMT capable MIPS: Netlogic: Add support for XLP 3XX cores MIPS: Netlogic: Merge some of XLR/XLP wakup code MIPS: Netlogic: Add default XLP config. ... Fix up trivial conflicts in arch/mips/kernel/{perf_event_mipsxx.c, traps.c} and drivers/tty/serial/Makefile
Diffstat (limited to 'arch/mips/alchemy/common/vss.c')
-rw-r--r--arch/mips/alchemy/common/vss.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/arch/mips/alchemy/common/vss.c b/arch/mips/alchemy/common/vss.c
new file mode 100644
index 00000000000..d23b1444d36
--- /dev/null
+++ b/arch/mips/alchemy/common/vss.c
@@ -0,0 +1,84 @@
+/*
+ * Au1300 media block power gating (VSS)
+ *
+ * This is a stop-gap solution until I have the clock framework integration
+ * ready. This stuff here really must be handled transparently when clocks
+ * for various media blocks are enabled/disabled.
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define VSS_GATE 0x00 /* gate wait timers */
+#define VSS_CLKRST 0x04 /* clock/block control */
+#define VSS_FTR 0x08 /* footers */
+
+#define VSS_ADDR(blk) (KSEG1ADDR(AU1300_VSS_PHYS_ADDR) + (blk * 0x0c))
+
+static DEFINE_SPINLOCK(au1300_vss_lock);
+
+/* enable a block as outlined in the databook */
+static inline void __enable_block(int block)
+{
+ void __iomem *base = (void __iomem *)VSS_ADDR(block);
+
+ __raw_writel(3, base + VSS_CLKRST); /* enable clock, assert reset */
+ wmb();
+
+ __raw_writel(0x01fffffe, base + VSS_GATE); /* maximum setup time */
+ wmb();
+
+ /* enable footers in sequence */
+ __raw_writel(0x01, base + VSS_FTR);
+ wmb();
+ __raw_writel(0x03, base + VSS_FTR);
+ wmb();
+ __raw_writel(0x07, base + VSS_FTR);
+ wmb();
+ __raw_writel(0x0f, base + VSS_FTR);
+ wmb();
+
+ __raw_writel(0x01ffffff, base + VSS_GATE); /* start FSM too */
+ wmb();
+
+ __raw_writel(2, base + VSS_CLKRST); /* deassert reset */
+ wmb();
+
+ __raw_writel(0x1f, base + VSS_FTR); /* enable isolation cells */
+ wmb();
+}
+
+/* disable a block as outlined in the databook */
+static inline void __disable_block(int block)
+{
+ void __iomem *base = (void __iomem *)VSS_ADDR(block);
+
+ __raw_writel(0x0f, base + VSS_FTR); /* disable isolation cells */
+ wmb();
+ __raw_writel(0, base + VSS_GATE); /* disable FSM */
+ wmb();
+ __raw_writel(3, base + VSS_CLKRST); /* assert reset */
+ wmb();
+ __raw_writel(1, base + VSS_CLKRST); /* disable clock */
+ wmb();
+ __raw_writel(0, base + VSS_FTR); /* disable all footers */
+ wmb();
+}
+
+void au1300_vss_block_control(int block, int enable)
+{
+ unsigned long flags;
+
+ if (alchemy_get_cputype() != ALCHEMY_CPU_AU1300)
+ return;
+
+ /* only one block at a time */
+ spin_lock_irqsave(&au1300_vss_lock, flags);
+ if (enable)
+ __enable_block(block);
+ else
+ __disable_block(block);
+ spin_unlock_irqrestore(&au1300_vss_lock, flags);
+}
+EXPORT_SYMBOL_GPL(au1300_vss_block_control);