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