]> Git Repo - J-linux.git/blob - drivers/cpufreq/bmips-cpufreq.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / cpufreq / bmips-cpufreq.c
1 /*
2  * CPU frequency scaling for Broadcom BMIPS SoCs
3  *
4  * Copyright (c) 2017 Broadcom
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation version 2.
9  *
10  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11  * kind, whether express or implied; without even the implied warranty
12  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15
16 #include <linux/cpufreq.h>
17 #include <linux/module.h>
18 #include <linux/of_address.h>
19 #include <linux/slab.h>
20
21 /* for mips_hpt_frequency */
22 #include <asm/time.h>
23
24 #define BMIPS_CPUFREQ_PREFIX    "bmips"
25 #define BMIPS_CPUFREQ_NAME      BMIPS_CPUFREQ_PREFIX "-cpufreq"
26
27 #define TRANSITION_LATENCY      (25 * 1000)     /* 25 us */
28
29 #define BMIPS5_CLK_DIV_SET_SHIFT        0x7
30 #define BMIPS5_CLK_DIV_SHIFT            0x4
31 #define BMIPS5_CLK_DIV_MASK             0xf
32
33 enum bmips_type {
34         BMIPS5000,
35         BMIPS5200,
36 };
37
38 struct cpufreq_compat {
39         const char *compatible;
40         unsigned int bmips_type;
41         unsigned int clk_mult;
42         unsigned int max_freqs;
43 };
44
45 #define BMIPS(c, t, m, f) { \
46         .compatible = c, \
47         .bmips_type = (t), \
48         .clk_mult = (m), \
49         .max_freqs = (f), \
50 }
51
52 static struct cpufreq_compat bmips_cpufreq_compat[] = {
53         BMIPS("brcm,bmips5000", BMIPS5000, 8, 4),
54         BMIPS("brcm,bmips5200", BMIPS5200, 8, 4),
55         { }
56 };
57
58 static struct cpufreq_compat *priv;
59
60 static int htp_freq_to_cpu_freq(unsigned int clk_mult)
61 {
62         return mips_hpt_frequency * clk_mult / 1000;
63 }
64
65 static struct cpufreq_frequency_table *
66 bmips_cpufreq_get_freq_table(const struct cpufreq_policy *policy)
67 {
68         struct cpufreq_frequency_table *table;
69         unsigned long cpu_freq;
70         int i;
71
72         cpu_freq = htp_freq_to_cpu_freq(priv->clk_mult);
73
74         table = kmalloc_array(priv->max_freqs + 1, sizeof(*table), GFP_KERNEL);
75         if (!table)
76                 return ERR_PTR(-ENOMEM);
77
78         for (i = 0; i < priv->max_freqs; i++) {
79                 table[i].frequency = cpu_freq / (1 << i);
80                 table[i].driver_data = i;
81         }
82         table[i].frequency = CPUFREQ_TABLE_END;
83
84         return table;
85 }
86
87 static unsigned int bmips_cpufreq_get(unsigned int cpu)
88 {
89         unsigned int div;
90         uint32_t mode;
91
92         switch (priv->bmips_type) {
93         case BMIPS5200:
94         case BMIPS5000:
95                 mode = read_c0_brcm_mode();
96                 div = ((mode >> BMIPS5_CLK_DIV_SHIFT) & BMIPS5_CLK_DIV_MASK);
97                 break;
98         default:
99                 div = 0;
100         }
101
102         return htp_freq_to_cpu_freq(priv->clk_mult) / (1 << div);
103 }
104
105 static int bmips_cpufreq_target_index(struct cpufreq_policy *policy,
106                                       unsigned int index)
107 {
108         unsigned int div = policy->freq_table[index].driver_data;
109
110         switch (priv->bmips_type) {
111         case BMIPS5200:
112         case BMIPS5000:
113                 change_c0_brcm_mode(BMIPS5_CLK_DIV_MASK << BMIPS5_CLK_DIV_SHIFT,
114                                     (1 << BMIPS5_CLK_DIV_SET_SHIFT) |
115                                     (div << BMIPS5_CLK_DIV_SHIFT));
116                 break;
117         default:
118                 return -ENOTSUPP;
119         }
120
121         return 0;
122 }
123
124 static void bmips_cpufreq_exit(struct cpufreq_policy *policy)
125 {
126         kfree(policy->freq_table);
127 }
128
129 static int bmips_cpufreq_init(struct cpufreq_policy *policy)
130 {
131         struct cpufreq_frequency_table *freq_table;
132
133         freq_table = bmips_cpufreq_get_freq_table(policy);
134         if (IS_ERR(freq_table)) {
135                 pr_err("%s: couldn't determine frequency table (%ld).\n",
136                         BMIPS_CPUFREQ_NAME, PTR_ERR(freq_table));
137                 return PTR_ERR(freq_table);
138         }
139
140         cpufreq_generic_init(policy, freq_table, TRANSITION_LATENCY);
141         pr_info("%s: registered\n", BMIPS_CPUFREQ_NAME);
142
143         return 0;
144 }
145
146 static struct cpufreq_driver bmips_cpufreq_driver = {
147         .flags          = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
148         .verify         = cpufreq_generic_frequency_table_verify,
149         .target_index   = bmips_cpufreq_target_index,
150         .get            = bmips_cpufreq_get,
151         .init           = bmips_cpufreq_init,
152         .exit           = bmips_cpufreq_exit,
153         .attr           = cpufreq_generic_attr,
154         .name           = BMIPS_CPUFREQ_PREFIX,
155 };
156
157 static int __init bmips_cpufreq_driver_init(void)
158 {
159         struct cpufreq_compat *cc;
160         struct device_node *np;
161
162         for (cc = bmips_cpufreq_compat; cc->compatible; cc++) {
163                 np = of_find_compatible_node(NULL, "cpu", cc->compatible);
164                 if (np) {
165                         of_node_put(np);
166                         priv = cc;
167                         break;
168                 }
169         }
170
171         /* We hit the guard element of the array. No compatible CPU found. */
172         if (!cc->compatible)
173                 return -ENODEV;
174
175         return cpufreq_register_driver(&bmips_cpufreq_driver);
176 }
177 module_init(bmips_cpufreq_driver_init);
178
179 static void __exit bmips_cpufreq_driver_exit(void)
180 {
181         cpufreq_unregister_driver(&bmips_cpufreq_driver);
182 }
183 module_exit(bmips_cpufreq_driver_exit);
184
185 MODULE_AUTHOR("Markus Mayer <[email protected]>");
186 MODULE_DESCRIPTION("CPUfreq driver for Broadcom BMIPS SoCs");
187 MODULE_LICENSE("GPL");
This page took 0.035965 seconds and 4 git commands to generate.