1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * MMP PMU power island support 4 * 5 * Copyright (C) 2020 Lubomir Rintel <lkundrak@v3.sk> 6 */ 7 8 #include <linux/pm_domain.h> 9 #include <linux/slab.h> 10 #include <linux/io.h> 11 12 #include "clk.h" 13 14 #define to_mmp_pm_domain(genpd) container_of(genpd, struct mmp_pm_domain, genpd) 15 16 struct mmp_pm_domain { 17 struct generic_pm_domain genpd; 18 void __iomem *reg; 19 spinlock_t *lock; 20 u32 power_on; 21 u32 reset; 22 u32 clock_enable; 23 unsigned int flags; 24 }; 25 26 static int mmp_pm_domain_power_on(struct generic_pm_domain *genpd) 27 { 28 struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd); 29 unsigned long flags = 0; 30 u32 val; 31 32 if (pm_domain->lock) 33 spin_lock_irqsave(pm_domain->lock, flags); 34 35 val = readl(pm_domain->reg); 36 37 /* Turn on the power island */ 38 val |= pm_domain->power_on; 39 writel(val, pm_domain->reg); 40 41 /* Disable isolation */ 42 val |= 0x100; 43 writel(val, pm_domain->reg); 44 45 /* Some blocks need to be reset after a power up */ 46 if (pm_domain->reset || pm_domain->clock_enable) { 47 u32 after_power_on = val; 48 49 val &= ~pm_domain->reset; 50 writel(val, pm_domain->reg); 51 52 val |= pm_domain->clock_enable; 53 writel(val, pm_domain->reg); 54 55 val |= pm_domain->reset; 56 writel(val, pm_domain->reg); 57 58 writel(after_power_on, pm_domain->reg); 59 } 60 61 if (pm_domain->lock) 62 spin_unlock_irqrestore(pm_domain->lock, flags); 63 64 return 0; 65 } 66 67 static int mmp_pm_domain_power_off(struct generic_pm_domain *genpd) 68 { 69 struct mmp_pm_domain *pm_domain = to_mmp_pm_domain(genpd); 70 unsigned long flags = 0; 71 u32 val; 72 73 if (pm_domain->flags & MMP_PM_DOMAIN_NO_DISABLE) 74 return 0; 75 76 if (pm_domain->lock) 77 spin_lock_irqsave(pm_domain->lock, flags); 78 79 /* Turn off and isolate the the power island. */ 80 val = readl(pm_domain->reg); 81 val &= ~pm_domain->power_on; 82 val &= ~0x100; 83 writel(val, pm_domain->reg); 84 85 if (pm_domain->lock) 86 spin_unlock_irqrestore(pm_domain->lock, flags); 87 88 return 0; 89 } 90 91 struct generic_pm_domain *mmp_pm_domain_register(const char *name, 92 void __iomem *reg, 93 u32 power_on, u32 reset, u32 clock_enable, 94 unsigned int flags, spinlock_t *lock) 95 { 96 struct mmp_pm_domain *pm_domain; 97 98 pm_domain = kzalloc(sizeof(*pm_domain), GFP_KERNEL); 99 if (!pm_domain) 100 return ERR_PTR(-ENOMEM); 101 102 pm_domain->reg = reg; 103 pm_domain->power_on = power_on; 104 pm_domain->reset = reset; 105 pm_domain->clock_enable = clock_enable; 106 pm_domain->flags = flags; 107 pm_domain->lock = lock; 108 109 pm_genpd_init(&pm_domain->genpd, NULL, true); 110 pm_domain->genpd.name = name; 111 pm_domain->genpd.power_on = mmp_pm_domain_power_on; 112 pm_domain->genpd.power_off = mmp_pm_domain_power_off; 113 114 return &pm_domain->genpd; 115 } 116