11541Srgrimes// SPDX-License-Identifier: GPL-2.0-or-later 21541Srgrimes/* 31541Srgrimes * MMP PMU power island support 41541Srgrimes * 51541Srgrimes * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk> 61541Srgrimes */ 71541Srgrimes 81541Srgrimes#include <linux/pm_domain.h> 91541Srgrimes#include <linux/slab.h> 101541Srgrimes#include <linux/io.h> 111541Srgrimes 121541Srgrimes#include "clk.h" 131541Srgrimes 141541Srgrimes#define to_mmp_pm_domain(genpd) container_of(genpd, struct mmp_pm_domain, genpd) 151541Srgrimes 161541Srgrimesstruct mmp_pm_domain { 171541Srgrimes struct generic_pm_domain genpd; 181541Srgrimes void __iomem *reg; 191541Srgrimes spinlock_t *lock; 201541Srgrimes u32 power_on; 211541Srgrimes u32 reset; 221541Srgrimes u32 clock_enable; 231541Srgrimes unsigned int flags; 241541Srgrimes}; 251541Srgrimes 261541Srgrimesstatic int mmp_pm_domain_power_on(struct generic_pm_domain *genpd) 271541Srgrimes{ 281541Srgrimes struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd); 291541Srgrimes unsigned long flags = 0; 301541Srgrimes u32 val; 311541Srgrimes 321541Srgrimes if (pm_domain->lock) 331541Srgrimes spin_lock_irqsave(pm_domain->lock, flags); 3450477Speter 351541Srgrimes val = readl(pm_domain->reg); 361541Srgrimes 372165Spaul /* Turn on the power island */ 382811Sbde val |= pm_domain->power_on; 392165Spaul writel(val, pm_domain->reg); 4076166Smarkm 4176166Smarkm /* Disable isolation */ 4276166Smarkm val |= 0x100; 4376166Smarkm writel(val, pm_domain->reg); 4476166Smarkm 4576166Smarkm /* Some blocks need to be reset after a power up */ 461541Srgrimes if (pm_domain->reset || pm_domain->clock_enable) { 47101848Srwatson u32 after_power_on = val; 4876166Smarkm 49103187Sbde val &= ~pm_domain->reset; 5076166Smarkm writel(val, pm_domain->reg); 51103187Sbde 5270834Swollman val |= pm_domain->clock_enable; 5334924Sbde writel(val, pm_domain->reg); 5454803Srwatson 55103849Sjeff val |= pm_domain->reset; 561541Srgrimes writel(val, pm_domain->reg); 571541Srgrimes 581541Srgrimes writel(after_power_on, pm_domain->reg); 591541Srgrimes } 601541Srgrimes 611541Srgrimes if (pm_domain->lock) 621541Srgrimes spin_unlock_irqrestore(pm_domain->lock, flags); 631541Srgrimes 641541Srgrimes return 0; 651541Srgrimes} 661541Srgrimes 671541Srgrimesstatic int mmp_pm_domain_power_off(struct generic_pm_domain *genpd) 681541Srgrimes{ 691541Srgrimes struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd); 701541Srgrimes unsigned long flags = 0; 711541Srgrimes u32 val; 7260938Sjake 731541Srgrimes if (pm_domain->flags & MMP_PM_DOMAIN_NO_DISABLE) 7492719Salfred return 0; 7559652Sgreen 7612158Sbde if (pm_domain->lock) 7790791Sphk spin_lock_irqsave(pm_domain->lock, flags); 7890791Sphk 7990791Sphk /* Turn off and isolate the power island. */ 8090791Sphk val = readl(pm_domain->reg); 8190791Sphk val &= ~pm_domain->power_on; 8290791Sphk val &= ~0x100; 8390791Sphk writel(val, pm_domain->reg); 8422521Sdyson 8522521Sdyson if (pm_domain->lock) 86101368Sjeff spin_unlock_irqrestore(pm_domain->lock, flags); 87101368Sjeff 88103926Sjeff return 0; 89101491Sjeff} 90101491Sjeff 91101491Sjeffstruct generic_pm_domain *mmp_pm_domain_register(const char *name, 92101491Sjeff void __iomem *reg, 93103926Sjeff u32 power_on, u32 reset, u32 clock_enable, 94103926Sjeff unsigned int flags, spinlock_t *lock) 95103926Sjeff{ 96101491Sjeff struct mmp_pm_domain *pm_domain; 97101491Sjeff 98101491Sjeff pm_domain = kzalloc(sizeof(*pm_domain), GFP_KERNEL); 99101491Sjeff if (!pm_domain) 10022521Sdyson return ERR_PTR(-ENOMEM); 101101368Sjeff 1021541Srgrimes pm_domain->reg = reg; 103101491Sjeff pm_domain->power_on = power_on; 104101491Sjeff pm_domain->reset = reset; 105101491Sjeff pm_domain->clock_enable = clock_enable; 106101491Sjeff pm_domain->flags = flags; 107101491Sjeff pm_domain->lock = lock; 108101491Sjeff 109103926Sjeff pm_genpd_init(&pm_domain->genpd, NULL, true); 110103926Sjeff pm_domain->genpd.name = name; 111103926Sjeff pm_domain->genpd.power_on = mmp_pm_domain_power_on; 112103926Sjeff pm_domain->genpd.power_off = mmp_pm_domain_power_off; 113101491Sjeff 114103926Sjeff return &pm_domain->genpd; 115103926Sjeff} 116103926Sjeff