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