116 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * MMP PMU power island support4 *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 16struct 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 26static 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 67static 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 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 91struct 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