Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Au1300 media block power gating (VSS)
0004  *
0005  * This is a stop-gap solution until I have the clock framework integration
0006  * ready. This stuff here really must be handled transparently when clocks
0007  * for various media blocks are enabled/disabled.
0008  */
0009 
0010 #include <linux/export.h>
0011 #include <linux/spinlock.h>
0012 #include <asm/mach-au1x00/au1000.h>
0013 
0014 #define VSS_GATE    0x00    /* gate wait timers */
0015 #define VSS_CLKRST  0x04    /* clock/block control */
0016 #define VSS_FTR     0x08    /* footers */
0017 
0018 #define VSS_ADDR(blk)   (KSEG1ADDR(AU1300_VSS_PHYS_ADDR) + (blk * 0x0c))
0019 
0020 static DEFINE_SPINLOCK(au1300_vss_lock);
0021 
0022 /* enable a block as outlined in the databook */
0023 static inline void __enable_block(int block)
0024 {
0025     void __iomem *base = (void __iomem *)VSS_ADDR(block);
0026 
0027     __raw_writel(3, base + VSS_CLKRST); /* enable clock, assert reset */
0028     wmb();
0029 
0030     __raw_writel(0x01fffffe, base + VSS_GATE); /* maximum setup time */
0031     wmb();
0032 
0033     /* enable footers in sequence */
0034     __raw_writel(0x01, base + VSS_FTR);
0035     wmb();
0036     __raw_writel(0x03, base + VSS_FTR);
0037     wmb();
0038     __raw_writel(0x07, base + VSS_FTR);
0039     wmb();
0040     __raw_writel(0x0f, base + VSS_FTR);
0041     wmb();
0042 
0043     __raw_writel(0x01ffffff, base + VSS_GATE); /* start FSM too */
0044     wmb();
0045 
0046     __raw_writel(2, base + VSS_CLKRST); /* deassert reset */
0047     wmb();
0048 
0049     __raw_writel(0x1f, base + VSS_FTR); /* enable isolation cells */
0050     wmb();
0051 }
0052 
0053 /* disable a block as outlined in the databook */
0054 static inline void __disable_block(int block)
0055 {
0056     void __iomem *base = (void __iomem *)VSS_ADDR(block);
0057 
0058     __raw_writel(0x0f, base + VSS_FTR); /* disable isolation cells */
0059     wmb();
0060     __raw_writel(0, base + VSS_GATE);   /* disable FSM */
0061     wmb();
0062     __raw_writel(3, base + VSS_CLKRST); /* assert reset */
0063     wmb();
0064     __raw_writel(1, base + VSS_CLKRST); /* disable clock */
0065     wmb();
0066     __raw_writel(0, base + VSS_FTR);    /* disable all footers */
0067     wmb();
0068 }
0069 
0070 void au1300_vss_block_control(int block, int enable)
0071 {
0072     unsigned long flags;
0073 
0074     if (alchemy_get_cputype() != ALCHEMY_CPU_AU1300)
0075         return;
0076 
0077     /* only one block at a time */
0078     spin_lock_irqsave(&au1300_vss_lock, flags);
0079     if (enable)
0080         __enable_block(block);
0081     else
0082         __disable_block(block);
0083     spin_unlock_irqrestore(&au1300_vss_lock, flags);
0084 }
0085 EXPORT_SYMBOL_GPL(au1300_vss_block_control);