cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pwr-island.c (2604B)


      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
     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}