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