18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Au1300 media block power gating (VSS) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This is a stop-gap solution until I have the clock framework integration 68c2ecf20Sopenharmony_ci * ready. This stuff here really must be handled transparently when clocks 78c2ecf20Sopenharmony_ci * for various media blocks are enabled/disabled. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/export.h> 118c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 128c2ecf20Sopenharmony_ci#include <asm/mach-au1x00/au1000.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define VSS_GATE 0x00 /* gate wait timers */ 158c2ecf20Sopenharmony_ci#define VSS_CLKRST 0x04 /* clock/block control */ 168c2ecf20Sopenharmony_ci#define VSS_FTR 0x08 /* footers */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define VSS_ADDR(blk) (KSEG1ADDR(AU1300_VSS_PHYS_ADDR) + (blk * 0x0c)) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(au1300_vss_lock); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* enable a block as outlined in the databook */ 238c2ecf20Sopenharmony_cistatic inline void __enable_block(int block) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci void __iomem *base = (void __iomem *)VSS_ADDR(block); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci __raw_writel(3, base + VSS_CLKRST); /* enable clock, assert reset */ 288c2ecf20Sopenharmony_ci wmb(); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci __raw_writel(0x01fffffe, base + VSS_GATE); /* maximum setup time */ 318c2ecf20Sopenharmony_ci wmb(); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* enable footers in sequence */ 348c2ecf20Sopenharmony_ci __raw_writel(0x01, base + VSS_FTR); 358c2ecf20Sopenharmony_ci wmb(); 368c2ecf20Sopenharmony_ci __raw_writel(0x03, base + VSS_FTR); 378c2ecf20Sopenharmony_ci wmb(); 388c2ecf20Sopenharmony_ci __raw_writel(0x07, base + VSS_FTR); 398c2ecf20Sopenharmony_ci wmb(); 408c2ecf20Sopenharmony_ci __raw_writel(0x0f, base + VSS_FTR); 418c2ecf20Sopenharmony_ci wmb(); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci __raw_writel(0x01ffffff, base + VSS_GATE); /* start FSM too */ 448c2ecf20Sopenharmony_ci wmb(); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci __raw_writel(2, base + VSS_CLKRST); /* deassert reset */ 478c2ecf20Sopenharmony_ci wmb(); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci __raw_writel(0x1f, base + VSS_FTR); /* enable isolation cells */ 508c2ecf20Sopenharmony_ci wmb(); 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* disable a block as outlined in the databook */ 548c2ecf20Sopenharmony_cistatic inline void __disable_block(int block) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci void __iomem *base = (void __iomem *)VSS_ADDR(block); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci __raw_writel(0x0f, base + VSS_FTR); /* disable isolation cells */ 598c2ecf20Sopenharmony_ci wmb(); 608c2ecf20Sopenharmony_ci __raw_writel(0, base + VSS_GATE); /* disable FSM */ 618c2ecf20Sopenharmony_ci wmb(); 628c2ecf20Sopenharmony_ci __raw_writel(3, base + VSS_CLKRST); /* assert reset */ 638c2ecf20Sopenharmony_ci wmb(); 648c2ecf20Sopenharmony_ci __raw_writel(1, base + VSS_CLKRST); /* disable clock */ 658c2ecf20Sopenharmony_ci wmb(); 668c2ecf20Sopenharmony_ci __raw_writel(0, base + VSS_FTR); /* disable all footers */ 678c2ecf20Sopenharmony_ci wmb(); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_civoid au1300_vss_block_control(int block, int enable) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci unsigned long flags; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (alchemy_get_cputype() != ALCHEMY_CPU_AU1300) 758c2ecf20Sopenharmony_ci return; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* only one block at a time */ 788c2ecf20Sopenharmony_ci spin_lock_irqsave(&au1300_vss_lock, flags); 798c2ecf20Sopenharmony_ci if (enable) 808c2ecf20Sopenharmony_ci __enable_block(block); 818c2ecf20Sopenharmony_ci else 828c2ecf20Sopenharmony_ci __disable_block(block); 838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&au1300_vss_lock, flags); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(au1300_vss_block_control); 86