blob: b6204cb5a72ecdd03acd4f394410c1647feb1462 [file] [log] [blame]
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001/*
2 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
Deepak Katragadda9abd7942017-06-13 14:20:09 -070014#define pr_fmt(fmt) "clk: %s: " fmt, __func__
Deepak Katragadda7abd9312016-12-21 14:18:00 -080015
16#include <linux/debugfs.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/io.h>
Deepak Katragadda7abd9312016-12-21 14:18:00 -080021#include <linux/err.h>
22#include <linux/errno.h>
23#include <linux/clk.h>
24#include <linux/clk-provider.h>
25#include <linux/cpu.h>
26#include <linux/platform_device.h>
27#include <linux/of_platform.h>
28#include <linux/pm_opp.h>
Deepak Katragadda7abd9312016-12-21 14:18:00 -080029#include <linux/interrupt.h>
Deepak Katragadda7abd9312016-12-21 14:18:00 -080030#include <linux/uaccess.h>
31#include <linux/sched.h>
Stephen Boyd0c29ef62017-05-05 10:41:22 -070032#include <linux/cpufreq.h>
33#include <linux/slab.h>
Deepak Katragadda02617bd2017-11-10 16:03:43 -080034#include <linux/regulator/consumer.h>
Deepak Katragadda7abd9312016-12-21 14:18:00 -080035#include <dt-bindings/clock/qcom,cpucc-sdm845.h>
Deepak Katragadda02617bd2017-11-10 16:03:43 -080036#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
Deepak Katragadda7abd9312016-12-21 14:18:00 -080037
38#include "common.h"
39#include "clk-regmap.h"
Deepak Katragadda7abd9312016-12-21 14:18:00 -080040#include "clk-voter.h"
Deepak Katragaddabca4a872017-04-24 15:51:03 -070041#include "clk-debug.h"
Deepak Katragadda7abd9312016-12-21 14:18:00 -080042
Stephen Boyd0c29ef62017-05-05 10:41:22 -070043#define OSM_INIT_RATE 300000000UL
Deepak Katragadda8ee6b5b82017-07-24 16:47:10 -070044#define XO_RATE 19200000UL
Deepak Katragadda7abd9312016-12-21 14:18:00 -080045#define OSM_TABLE_SIZE 40
46#define SINGLE_CORE 1
47#define MAX_CLUSTER_CNT 3
48#define MAX_MEM_ACC_VAL_PER_LEVEL 3
Deepak Katragadda7abd9312016-12-21 14:18:00 -080049#define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16)
50
Deepak Katragadda7abd9312016-12-21 14:18:00 -080051#define OSM_REG_SIZE 32
52
Deepak Katragadda7abd9312016-12-21 14:18:00 -080053#define ENABLE_REG 0x0
54#define FREQ_REG 0x110
55#define VOLT_REG 0x114
Deepak Katragadda7abd9312016-12-21 14:18:00 -080056#define CORE_DCVS_CTRL 0xbc
Deepak Katragadda7abd9312016-12-21 14:18:00 -080057
Deepak Katragaddafc6bd3c2017-05-12 12:03:49 -070058#define DCVS_PERF_STATE_DESIRED_REG_0_V1 0x780
59#define DCVS_PERF_STATE_DESIRED_REG_0_V2 0x920
Odelu Kukatla3799c7c2017-08-20 20:48:45 +053060#define DCVS_PERF_STATE_DESIRED_REG(n, v1) \
61 (((v1) ? DCVS_PERF_STATE_DESIRED_REG_0_V1 \
62 : DCVS_PERF_STATE_DESIRED_REG_0_V2) + 4 * (n))
Deepak Katragaddafc6bd3c2017-05-12 12:03:49 -070063
64#define OSM_CYCLE_COUNTER_STATUS_REG_0_V1 0x7d0
65#define OSM_CYCLE_COUNTER_STATUS_REG_0_V2 0x9c0
Odelu Kukatla3799c7c2017-08-20 20:48:45 +053066#define OSM_CYCLE_COUNTER_STATUS_REG(n, v1) \
67 (((v1) ? OSM_CYCLE_COUNTER_STATUS_REG_0_V1 \
68 : OSM_CYCLE_COUNTER_STATUS_REG_0_V2) + 4 * (n))
Deepak Katragadda7abd9312016-12-21 14:18:00 -080069
Deepak Katragadda02617bd2017-11-10 16:03:43 -080070static DEFINE_VDD_REGS_INIT(vdd_l3_mx_ao, 1);
71static DEFINE_VDD_REGS_INIT(vdd_pwrcl_mx_ao, 1);
72
Deepak Katragadda7abd9312016-12-21 14:18:00 -080073struct osm_entry {
74 u16 virtual_corner;
75 u16 open_loop_volt;
Deepak Katragadda7abd9312016-12-21 14:18:00 -080076 long frequency;
Deepak Katragadda9c360882017-11-21 17:17:54 -080077 u16 ccount;
Deepak Katragadda7abd9312016-12-21 14:18:00 -080078};
79
80struct clk_osm {
81 struct clk_hw hw;
82 struct osm_entry osm_table[OSM_TABLE_SIZE];
83 struct dentry *debugfs;
Deepak Katragaddacc3e9472017-07-07 10:30:15 -070084 void __iomem *vbase;
85 phys_addr_t pbase;
Deepak Katragadda7abd9312016-12-21 14:18:00 -080086 spinlock_t lock;
Deepak Katragaddacc3e9472017-07-07 10:30:15 -070087 bool per_core_dcvs;
Deepak Katragadda7abd9312016-12-21 14:18:00 -080088 u32 num_entries;
89 u32 cluster_num;
90 u32 core_num;
David Collins5c9a8e62017-12-05 12:14:42 -080091 unsigned long rate;
Deepak Katragadda7abd9312016-12-21 14:18:00 -080092 u64 total_cycle_counter;
93 u32 prev_cycle_counter;
Odelu Kukatla3799c7c2017-08-20 20:48:45 +053094 u32 max_core_count;
Deepak Katragadda02617bd2017-11-10 16:03:43 -080095 u32 mx_turbo_freq;
Deepak Katragadda7abd9312016-12-21 14:18:00 -080096};
97
Odelu Kukatla3799c7c2017-08-20 20:48:45 +053098static bool is_sdm845v1;
Deepak Katragaddafc6bd3c2017-05-12 12:03:49 -070099
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800100static inline struct clk_osm *to_clk_osm(struct clk_hw *_hw)
101{
102 return container_of(_hw, struct clk_osm, hw);
103}
104
Deepak Katragaddacc3e9472017-07-07 10:30:15 -0700105static inline void clk_osm_write_reg(struct clk_osm *c, u32 val, u32 offset)
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800106{
Deepak Katragaddacc3e9472017-07-07 10:30:15 -0700107 writel_relaxed(val, c->vbase + offset);
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800108}
109
110static inline int clk_osm_read_reg(struct clk_osm *c, u32 offset)
111{
Deepak Katragaddacc3e9472017-07-07 10:30:15 -0700112 return readl_relaxed(c->vbase + offset);
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800113}
114
115static inline int clk_osm_read_reg_no_log(struct clk_osm *c, u32 offset)
116{
Deepak Katragaddacc3e9472017-07-07 10:30:15 -0700117 return readl_relaxed_no_log(c->vbase + offset);
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800118}
119
Deepak Katragaddacc3e9472017-07-07 10:30:15 -0700120static inline int clk_osm_mb(struct clk_osm *c)
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800121{
Deepak Katragaddacc3e9472017-07-07 10:30:15 -0700122 return readl_relaxed_no_log(c->vbase + ENABLE_REG);
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800123}
124
125static long clk_osm_list_rate(struct clk_hw *hw, unsigned int n,
126 unsigned long rate_max)
127{
128 if (n >= hw->init->num_rate_max)
129 return -ENXIO;
130 return hw->init->rate_max[n];
131}
132
133static inline bool is_better_rate(unsigned long req, unsigned long best,
134 unsigned long new)
135{
136 if (IS_ERR_VALUE(new))
137 return false;
138
139 return (req <= new && new < best) || (best < req && best < new);
140}
141
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800142static int clk_osm_search_table(struct osm_entry *table, int entries, long rate)
143{
144 int index;
145
146 for (index = 0; index < entries; index++) {
147 if (rate == table[index].frequency)
148 return index;
149 }
150
151 return -EINVAL;
152}
153
David Collins5c9a8e62017-12-05 12:14:42 -0800154static int clk_osm_set_rate(struct clk_hw *hw, unsigned long rate,
155 unsigned long parent_rate)
156{
157 struct clk_osm *c = to_clk_osm(hw);
158
159 c->rate = rate;
160
161 return 0;
162}
163
164static unsigned long clk_osm_recalc_rate(struct clk_hw *hw,
165 unsigned long parent_rate)
166{
167 struct clk_osm *c = to_clk_osm(hw);
168
169 return c->rate;
170}
171
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800172static long clk_osm_round_rate(struct clk_hw *hw, unsigned long rate,
173 unsigned long *parent_rate)
174{
175 int i;
176 unsigned long rrate = 0;
177
Deepak Katragaddaf424e012017-07-14 11:38:35 -0700178 if (!hw)
179 return -EINVAL;
180
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800181 /*
182 * If the rate passed in is 0, return the first frequency in the
183 * FMAX table.
184 */
185 if (!rate)
186 return hw->init->rate_max[0];
187
188 for (i = 0; i < hw->init->num_rate_max; i++) {
189 if (is_better_rate(rate, rrate, hw->init->rate_max[i])) {
190 rrate = hw->init->rate_max[i];
191 if (rate == rrate)
192 break;
193 }
194 }
195
196 pr_debug("%s: rate %lu, rrate %ld, Rate max %ld\n", __func__, rate,
197 rrate, hw->init->rate_max[i]);
198
199 return rrate;
200}
201
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800202static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
203 unsigned long parent_rate)
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800204{
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800205 struct clk_osm *c = to_clk_osm(hw);
206 struct clk_hw *p_hw = clk_hw_get_parent(hw);
207 struct clk_osm *parent = to_clk_osm(p_hw);
Deepak Katragadda8ee6b5b82017-07-24 16:47:10 -0700208 int index = 0;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800209
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800210 if (!c || !parent)
211 return -EINVAL;
212
213 index = clk_osm_search_table(parent->osm_table,
214 parent->num_entries, rate);
215 if (index < 0) {
216 pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate);
217 return -EINVAL;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800218 }
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800219
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800220 clk_osm_write_reg(parent, index,
221 DCVS_PERF_STATE_DESIRED_REG(c->core_num,
222 is_sdm845v1));
223
224 /* Make sure the write goes through before proceeding */
225 clk_osm_mb(parent);
226
227 return 0;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800228}
229
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800230static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw,
231 unsigned long parent_rate)
232{
233 struct clk_osm *c = to_clk_osm(hw);
234 struct clk_hw *p_hw = clk_hw_get_parent(hw);
235 struct clk_osm *parent = to_clk_osm(p_hw);
236 int index = 0;
237
238 if (!c || !parent)
239 return -EINVAL;
240
241 index = clk_osm_read_reg(parent,
242 DCVS_PERF_STATE_DESIRED_REG(c->core_num,
243 is_sdm845v1));
244 return parent->osm_table[index].frequency;
245}
246
247static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
248 unsigned long *parent_rate)
249{
250 struct clk_hw *parent_hw = clk_hw_get_parent(hw);
251
252 if (!parent_hw)
253 return -EINVAL;
254
255 *parent_rate = rate;
256 return clk_hw_round_rate(parent_hw, rate);
257}
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800258
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800259static int l3_clk_set_rate(struct clk_hw *hw, unsigned long rate,
260 unsigned long parent_rate)
261{
262 struct clk_osm *cpuclk = to_clk_osm(hw);
263 int index = 0;
264 unsigned long r_rate;
265
266 if (!cpuclk)
267 return -EINVAL;
268
269 r_rate = clk_osm_round_rate(hw, rate, NULL);
270
271 if (rate != r_rate) {
272 pr_err("invalid requested rate=%ld\n", rate);
273 return -EINVAL;
274 }
275
276 /* Convert rate to table index */
277 index = clk_osm_search_table(cpuclk->osm_table,
278 cpuclk->num_entries, r_rate);
279 if (index < 0) {
280 pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate);
281 return -EINVAL;
282 }
283 pr_debug("rate: %lu --> index %d\n", rate, index);
284
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530285 clk_osm_write_reg(cpuclk, index,
286 DCVS_PERF_STATE_DESIRED_REG(0, is_sdm845v1));
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800287
288 /* Make sure the write goes through before proceeding */
Deepak Katragaddacc3e9472017-07-07 10:30:15 -0700289 clk_osm_mb(cpuclk);
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800290
291 return 0;
292}
293
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800294static unsigned long l3_clk_recalc_rate(struct clk_hw *hw,
295 unsigned long parent_rate)
296{
297 struct clk_osm *cpuclk = to_clk_osm(hw);
298 int index = 0;
299
300 if (!cpuclk)
301 return -EINVAL;
302
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530303 index = clk_osm_read_reg(cpuclk,
304 DCVS_PERF_STATE_DESIRED_REG(0, is_sdm845v1));
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800305
306 pr_debug("%s: Index %d, freq %ld\n", __func__, index,
307 cpuclk->osm_table[index].frequency);
308
309 /* Convert index to frequency */
310 return cpuclk->osm_table[index].frequency;
311}
312
David Collins5c9a8e62017-12-05 12:14:42 -0800313static const struct clk_ops clk_ops_l3_osm = {
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800314 .round_rate = clk_osm_round_rate,
315 .list_rate = clk_osm_list_rate,
316 .recalc_rate = l3_clk_recalc_rate,
317 .set_rate = l3_clk_set_rate,
Deepak Katragaddabca4a872017-04-24 15:51:03 -0700318 .debug_init = clk_debug_measure_add,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800319};
320
David Collins5c9a8e62017-12-05 12:14:42 -0800321static const struct clk_ops clk_ops_core = {
322 .set_rate = clk_cpu_set_rate,
323 .round_rate = clk_cpu_round_rate,
324 .recalc_rate = clk_cpu_recalc_rate,
325 .debug_init = clk_debug_measure_add,
326};
327
328static const struct clk_ops clk_ops_cpu_osm = {
329 .set_rate = clk_osm_set_rate,
330 .round_rate = clk_osm_round_rate,
331 .recalc_rate = clk_osm_recalc_rate,
332 .list_rate = clk_osm_list_rate,
333 .debug_init = clk_debug_measure_add,
334};
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800335
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800336static struct clk_init_data osm_clks_init[] = {
337 [0] = {
338 .name = "l3_clk",
Deepak Katragadda3760e052017-04-20 13:41:32 -0700339 .parent_names = (const char *[]){ "bi_tcxo_ao" },
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800340 .num_parents = 1,
341 .ops = &clk_ops_l3_osm,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800342 .vdd_class = &vdd_l3_mx_ao,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800343 },
344 [1] = {
345 .name = "pwrcl_clk",
Deepak Katragadda3760e052017-04-20 13:41:32 -0700346 .parent_names = (const char *[]){ "bi_tcxo_ao" },
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800347 .num_parents = 1,
348 .ops = &clk_ops_cpu_osm,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800349 .vdd_class = &vdd_pwrcl_mx_ao,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800350 },
351 [2] = {
352 .name = "perfcl_clk",
Deepak Katragadda3760e052017-04-20 13:41:32 -0700353 .parent_names = (const char *[]){ "bi_tcxo_ao" },
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800354 .num_parents = 1,
355 .ops = &clk_ops_cpu_osm,
356 },
357};
358
359static struct clk_osm l3_clk = {
360 .cluster_num = 0,
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530361 .max_core_count = 4,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800362 .hw.init = &osm_clks_init[0],
363};
364
365static DEFINE_CLK_VOTER(l3_cluster0_vote_clk, l3_clk, 0);
366static DEFINE_CLK_VOTER(l3_cluster1_vote_clk, l3_clk, 0);
Deepak Katragadda43db9372017-10-12 10:55:55 -0700367static DEFINE_CLK_VOTER(l3_misc_vote_clk, l3_clk, 0);
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800368
369static struct clk_osm pwrcl_clk = {
370 .cluster_num = 1,
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530371 .max_core_count = 4,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800372 .hw.init = &osm_clks_init[1],
373};
374
375static struct clk_osm cpu0_pwrcl_clk = {
376 .core_num = 0,
377 .total_cycle_counter = 0,
378 .prev_cycle_counter = 0,
379 .hw.init = &(struct clk_init_data){
380 .name = "cpu0_pwrcl_clk",
381 .parent_names = (const char *[]){ "pwrcl_clk" },
382 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800383 .flags = CLK_SET_RATE_PARENT,
384 .ops = &clk_ops_core,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800385 },
386};
387
388static struct clk_osm cpu1_pwrcl_clk = {
389 .core_num = 1,
390 .total_cycle_counter = 0,
391 .prev_cycle_counter = 0,
392 .hw.init = &(struct clk_init_data){
393 .name = "cpu1_pwrcl_clk",
394 .parent_names = (const char *[]){ "pwrcl_clk" },
395 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800396 .flags = CLK_SET_RATE_PARENT,
397 .ops = &clk_ops_core,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800398 },
399};
400
401static struct clk_osm cpu2_pwrcl_clk = {
402 .core_num = 2,
403 .total_cycle_counter = 0,
404 .prev_cycle_counter = 0,
405 .hw.init = &(struct clk_init_data){
406 .name = "cpu2_pwrcl_clk",
407 .parent_names = (const char *[]){ "pwrcl_clk" },
408 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800409 .flags = CLK_SET_RATE_PARENT,
410 .ops = &clk_ops_core,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800411 },
412};
413
414static struct clk_osm cpu3_pwrcl_clk = {
415 .core_num = 3,
416 .total_cycle_counter = 0,
417 .prev_cycle_counter = 0,
418 .hw.init = &(struct clk_init_data){
419 .name = "cpu3_pwrcl_clk",
420 .parent_names = (const char *[]){ "pwrcl_clk" },
421 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800422 .flags = CLK_SET_RATE_PARENT,
423 .ops = &clk_ops_core,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800424 },
425};
426
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530427static struct clk_osm cpu4_pwrcl_clk = {
428 .core_num = 4,
429 .total_cycle_counter = 0,
430 .prev_cycle_counter = 0,
431 .hw.init = &(struct clk_init_data){
432 .name = "cpu4_pwrcl_clk",
433 .parent_names = (const char *[]){ "pwrcl_clk" },
434 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800435 .flags = CLK_SET_RATE_PARENT,
436 .ops = &clk_ops_core,
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530437 },
438};
439
440static struct clk_osm cpu5_pwrcl_clk = {
441 .core_num = 5,
442 .total_cycle_counter = 0,
443 .prev_cycle_counter = 0,
444 .hw.init = &(struct clk_init_data){
445 .name = "cpu5_pwrcl_clk",
446 .parent_names = (const char *[]){ "pwrcl_clk" },
447 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800448 .flags = CLK_SET_RATE_PARENT,
449 .ops = &clk_ops_core,
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530450 },
451};
452
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800453static struct clk_osm perfcl_clk = {
454 .cluster_num = 2,
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530455 .max_core_count = 4,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800456 .hw.init = &osm_clks_init[2],
457};
458
459
460static struct clk_osm cpu4_perfcl_clk = {
461 .core_num = 0,
462 .total_cycle_counter = 0,
463 .prev_cycle_counter = 0,
464 .hw.init = &(struct clk_init_data){
465 .name = "cpu4_perfcl_clk",
466 .parent_names = (const char *[]){ "perfcl_clk" },
467 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800468 .flags = CLK_SET_RATE_PARENT,
469 .ops = &clk_ops_core,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800470 },
471};
472
473static struct clk_osm cpu5_perfcl_clk = {
474 .core_num = 1,
475 .total_cycle_counter = 0,
476 .prev_cycle_counter = 0,
477 .hw.init = &(struct clk_init_data){
478 .name = "cpu5_perfcl_clk",
479 .parent_names = (const char *[]){ "perfcl_clk" },
480 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800481 .flags = CLK_SET_RATE_PARENT,
482 .ops = &clk_ops_core,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800483 },
484};
485
486static struct clk_osm cpu6_perfcl_clk = {
487 .core_num = 2,
488 .total_cycle_counter = 0,
489 .prev_cycle_counter = 0,
490 .hw.init = &(struct clk_init_data){
491 .name = "cpu6_perfcl_clk",
492 .parent_names = (const char *[]){ "perfcl_clk" },
493 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800494 .flags = CLK_SET_RATE_PARENT,
495 .ops = &clk_ops_core,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800496 },
497};
498
499static struct clk_osm cpu7_perfcl_clk = {
500 .core_num = 3,
501 .total_cycle_counter = 0,
502 .prev_cycle_counter = 0,
503 .hw.init = &(struct clk_init_data){
504 .name = "cpu7_perfcl_clk",
505 .parent_names = (const char *[]){ "perfcl_clk" },
506 .num_parents = 1,
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800507 .flags = CLK_SET_RATE_PARENT,
508 .ops = &clk_ops_core,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800509 },
510};
511
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800512static struct clk_hw *osm_qcom_clk_hws[] = {
513 [L3_CLK] = &l3_clk.hw,
514 [L3_CLUSTER0_VOTE_CLK] = &l3_cluster0_vote_clk.hw,
515 [L3_CLUSTER1_VOTE_CLK] = &l3_cluster1_vote_clk.hw,
Deepak Katragadda43db9372017-10-12 10:55:55 -0700516 [L3_MISC_VOTE_CLK] = &l3_misc_vote_clk.hw,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800517 [PWRCL_CLK] = &pwrcl_clk.hw,
518 [CPU0_PWRCL_CLK] = &cpu0_pwrcl_clk.hw,
519 [CPU1_PWRCL_CLK] = &cpu1_pwrcl_clk.hw,
520 [CPU2_PWRCL_CLK] = &cpu2_pwrcl_clk.hw,
521 [CPU3_PWRCL_CLK] = &cpu3_pwrcl_clk.hw,
522 [PERFCL_CLK] = &perfcl_clk.hw,
523 [CPU4_PERFCL_CLK] = &cpu4_perfcl_clk.hw,
524 [CPU5_PERFCL_CLK] = &cpu5_perfcl_clk.hw,
525 [CPU6_PERFCL_CLK] = &cpu6_perfcl_clk.hw,
526 [CPU7_PERFCL_CLK] = &cpu7_perfcl_clk.hw,
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530527 [CPU4_PWRCL_CLK] = NULL,
528 [CPU5_PWRCL_CLK] = NULL,
529};
530
531static struct clk_osm *clk_cpu_map[] = {
532 &cpu0_pwrcl_clk,
533 &cpu1_pwrcl_clk,
534 &cpu2_pwrcl_clk,
535 &cpu3_pwrcl_clk,
536 &cpu4_perfcl_clk,
537 &cpu5_perfcl_clk,
538 &cpu6_perfcl_clk,
539 &cpu7_perfcl_clk,
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800540};
541
542static struct clk_osm *logical_cpu_to_clk(int cpu)
543{
544 struct device_node *cpu_node;
545 const u32 *cell;
546 u64 hwid;
547 static struct clk_osm *cpu_clk_map[NR_CPUS];
548
Stephen Boyd406244f2017-05-19 14:52:57 -0700549 if (!cpu_clk_map[cpu]) {
550 cpu_node = of_get_cpu_node(cpu, NULL);
551 if (!cpu_node)
552 return NULL;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800553
Stephen Boyd406244f2017-05-19 14:52:57 -0700554 cell = of_get_property(cpu_node, "reg", NULL);
555 if (!cell) {
556 pr_err("%s: missing reg property\n",
557 cpu_node->full_name);
558 of_node_put(cpu_node);
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800559 return NULL;
560 }
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800561
Stephen Boyd406244f2017-05-19 14:52:57 -0700562 hwid = of_read_number(cell, of_n_addr_cells(cpu_node));
563 hwid = (hwid >> 8) & 0xff;
564 of_node_put(cpu_node);
565 if (hwid >= ARRAY_SIZE(clk_cpu_map)) {
566 pr_err("unsupported CPU number - %d (hw_id - %llu)\n",
567 cpu, hwid);
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800568 return NULL;
569 }
Stephen Boyd406244f2017-05-19 14:52:57 -0700570
571 cpu_clk_map[cpu] = clk_cpu_map[hwid];
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800572 }
573
Stephen Boyd406244f2017-05-19 14:52:57 -0700574 return cpu_clk_map[cpu];
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800575}
576
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700577static struct clk_osm *osm_configure_policy(struct cpufreq_policy *policy)
578{
579 int cpu;
580 struct clk_hw *parent, *c_parent;
581 struct clk_osm *first;
582 struct clk_osm *c, *n;
583
584 c = logical_cpu_to_clk(policy->cpu);
585 if (!c)
586 return NULL;
587
588 c_parent = clk_hw_get_parent(&c->hw);
589 if (!c_parent)
590 return NULL;
591
592 /*
593 * Don't put any other CPUs into the policy if we're doing
594 * per_core_dcvs
595 */
596 if (to_clk_osm(c_parent)->per_core_dcvs)
597 return c;
598
599 first = c;
600 /* Find CPUs that share the same clock domain */
601 for_each_possible_cpu(cpu) {
602 n = logical_cpu_to_clk(cpu);
603 if (!n)
604 continue;
605
606 parent = clk_hw_get_parent(&n->hw);
607 if (!parent)
608 return NULL;
609 if (parent != c_parent)
610 continue;
611
612 cpumask_set_cpu(cpu, policy->cpus);
613 if (n->core_num == 0)
614 first = n;
615 }
616
617 return first;
618}
619
620static void
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800621osm_set_index(struct clk_osm *c, unsigned int index)
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700622{
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800623 struct clk_hw *p_hw = clk_hw_get_parent(&c->hw);
624 struct clk_osm *parent = to_clk_osm(p_hw);
625 unsigned long rate = 0;
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700626
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800627 if (index >= OSM_TABLE_SIZE) {
628 pr_err("Passing an index (%u) that's greater than max (%d)\n",
629 index, OSM_TABLE_SIZE - 1);
630 return;
631 }
632
633 rate = parent->osm_table[index].frequency;
634 if (!rate)
635 return;
636
637 clk_set_rate(c->hw.clk, clk_round_rate(c->hw.clk, rate));
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700638}
639
640static int
641osm_cpufreq_target_index(struct cpufreq_policy *policy, unsigned int index)
642{
643 struct clk_osm *c = policy->driver_data;
644
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800645 osm_set_index(c, index);
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700646 return 0;
647}
648
649static unsigned int osm_cpufreq_get(unsigned int cpu)
650{
651 struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
652 struct clk_osm *c;
653 u32 index;
654
655 if (!policy)
656 return 0;
657
658 c = policy->driver_data;
Deepak Katragaddafc6bd3c2017-05-12 12:03:49 -0700659 index = clk_osm_read_reg(c,
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530660 DCVS_PERF_STATE_DESIRED_REG(c->core_num, is_sdm845v1));
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700661 return policy->freq_table[index].frequency;
662}
663
664static int osm_cpufreq_cpu_init(struct cpufreq_policy *policy)
665{
666 struct cpufreq_frequency_table *table;
667 struct clk_osm *c, *parent;
668 struct clk_hw *p_hw;
669 int ret;
Deepak Katragadda9c360882017-11-21 17:17:54 -0800670 unsigned int i, prev_cc = 0;
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700671 unsigned int xo_kHz;
672
673 c = osm_configure_policy(policy);
674 if (!c) {
675 pr_err("no clock for CPU%d\n", policy->cpu);
676 return -ENODEV;
677 }
678
679 p_hw = clk_hw_get_parent(&c->hw);
680 if (!p_hw) {
681 pr_err("no parent clock for CPU%d\n", policy->cpu);
682 return -ENODEV;
683 }
684
685 parent = to_clk_osm(p_hw);
Deepak Katragaddacc3e9472017-07-07 10:30:15 -0700686 c->vbase = parent->vbase;
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700687
688 p_hw = clk_hw_get_parent(p_hw);
689 if (!p_hw) {
690 pr_err("no xo clock for CPU%d\n", policy->cpu);
691 return -ENODEV;
692 }
693 xo_kHz = clk_hw_get_rate(p_hw) / 1000;
694
695 table = kcalloc(OSM_TABLE_SIZE + 1, sizeof(*table), GFP_KERNEL);
696 if (!table)
697 return -ENOMEM;
698
699 for (i = 0; i < OSM_TABLE_SIZE; i++) {
700 u32 data, src, div, lval, core_count;
701
702 data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE);
703 src = (data & GENMASK(31, 30)) >> 30;
704 div = (data & GENMASK(29, 28)) >> 28;
705 lval = data & GENMASK(7, 0);
706 core_count = CORE_COUNT_VAL(data);
707
708 if (!src)
709 table[i].frequency = OSM_INIT_RATE / 1000;
710 else
711 table[i].frequency = xo_kHz * lval;
712 table[i].driver_data = table[i].frequency;
713
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530714 if (core_count != parent->max_core_count)
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700715 table[i].frequency = CPUFREQ_ENTRY_INVALID;
716
Deepak Katragadda9c360882017-11-21 17:17:54 -0800717 /*
718 * Two of the same frequencies with the same core counts means
719 * end of table.
720 */
721 if (i > 0 && table[i - 1].driver_data == table[i].driver_data
722 && prev_cc == core_count) {
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700723 struct cpufreq_frequency_table *prev = &table[i - 1];
724
725 if (prev->frequency == CPUFREQ_ENTRY_INVALID) {
726 prev->flags = CPUFREQ_BOOST_FREQ;
727 prev->frequency = prev->driver_data;
728 }
729
730 break;
731 }
Deepak Katragadda9c360882017-11-21 17:17:54 -0800732 prev_cc = core_count;
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700733 }
734 table[i].frequency = CPUFREQ_TABLE_END;
735
736 ret = cpufreq_table_validate_and_show(policy, table);
737 if (ret) {
738 pr_err("%s: invalid frequency table: %d\n", __func__, ret);
739 goto err;
740 }
741
742 policy->driver_data = c;
Stephen Boyd0c29ef62017-05-05 10:41:22 -0700743 return 0;
744
745err:
746 kfree(table);
747 return ret;
748}
749
750static int osm_cpufreq_cpu_exit(struct cpufreq_policy *policy)
751{
752 kfree(policy->freq_table);
753 policy->freq_table = NULL;
754 return 0;
755}
756
757static struct freq_attr *osm_cpufreq_attr[] = {
758 &cpufreq_freq_attr_scaling_available_freqs,
759 &cpufreq_freq_attr_scaling_boost_freqs,
760 NULL
761};
762
763static struct cpufreq_driver qcom_osm_cpufreq_driver = {
764 .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK |
765 CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
766 .verify = cpufreq_generic_frequency_table_verify,
767 .target_index = osm_cpufreq_target_index,
768 .get = osm_cpufreq_get,
769 .init = osm_cpufreq_cpu_init,
770 .exit = osm_cpufreq_cpu_exit,
771 .name = "osm-cpufreq",
772 .attr = osm_cpufreq_attr,
773 .boost_enabled = true,
774};
775
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800776static u32 find_voltage(struct clk_osm *c, unsigned long rate)
777{
778 struct osm_entry *table = c->osm_table;
779 int entries = c->num_entries, i;
780
781 for (i = 0; i < entries; i++) {
782 if (rate == table[i].frequency) {
783 /* OPP table voltages have units of mV */
784 return table[i].open_loop_volt * 1000;
785 }
786 }
787
788 return -EINVAL;
789}
790
Deepak Katragaddaeda782e2017-10-12 11:06:28 -0700791static int add_opp(struct clk_osm *c, struct device **device_list, int count)
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800792{
793 unsigned long rate = 0;
794 u32 uv;
795 long rc;
Deepak Katragaddaeda782e2017-10-12 11:06:28 -0700796 int i, j = 0;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800797 unsigned long min_rate = c->hw.init->rate_max[0];
798 unsigned long max_rate =
799 c->hw.init->rate_max[c->hw.init->num_rate_max - 1];
800
801 while (1) {
802 rate = c->hw.init->rate_max[j++];
803 uv = find_voltage(c, rate);
804 if (uv <= 0) {
805 pr_warn("No voltage for %lu.\n", rate);
806 return -EINVAL;
807 }
808
Deepak Katragaddaeda782e2017-10-12 11:06:28 -0700809 for (i = 0; i < count; i++) {
810 rc = dev_pm_opp_add(device_list[i], rate, uv);
811 if (rc) {
812 pr_warn("failed to add OPP for %lu\n", rate);
813 return rc;
814 }
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800815 }
816
817 /*
818 * Print the OPP pair for the lowest and highest frequency for
819 * each device that we're populating. This is important since
820 * this information will be used by thermal mitigation and the
821 * scheduler.
822 */
Deepak Katragaddaeda782e2017-10-12 11:06:28 -0700823 if (rate == min_rate) {
824 for (i = 0; i < count; i++) {
825 pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n",
826 rate, uv, dev_name(device_list[i]));
827 }
828 }
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800829
830 if (rate == max_rate && max_rate != min_rate) {
Deepak Katragaddaeda782e2017-10-12 11:06:28 -0700831 for (i = 0; i < count; i++) {
832 pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n",
833 rate, uv, dev_name(device_list[i]));
834 }
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800835 break;
836 }
837
838 if (min_rate == max_rate)
839 break;
840 }
841 return 0;
842}
843
Deepak Katragaddaeda782e2017-10-12 11:06:28 -0700844static int derive_device_list(struct device **device_list,
845 struct device_node *np,
846 char *phandle_name, int count)
847{
848 int i;
849 struct platform_device *pdev;
850 struct device_node *dev_node;
851
852 for (i = 0; i < count; i++) {
853 dev_node = of_parse_phandle(np, phandle_name, i);
854 if (!dev_node) {
855 pr_err("Unable to get device_node pointer for opp-handle (%s)\n",
856 phandle_name);
857 return -ENODEV;
858 }
859
860 pdev = of_find_device_by_node(dev_node);
861 if (!pdev) {
862 pr_err("Unable to find platform_device node for opp-handle (%s)\n",
863 phandle_name);
864 return -ENODEV;
865 }
866 device_list[i] = &pdev->dev;
867 }
868 return 0;
869}
870
871static void populate_l3_opp_table(struct device_node *np, char *phandle_name)
872{
873 struct device **device_list;
874 int len, count, ret = 0;
875
876 if (of_find_property(np, phandle_name, &len)) {
877 count = len / sizeof(u32);
878
879 device_list = kcalloc(count, sizeof(struct device *),
880 GFP_KERNEL);
881 if (!device_list)
882 return;
883
884 ret = derive_device_list(device_list, np, phandle_name, count);
885 if (ret < 0) {
886 pr_err("Failed to fill device_list for %s\n",
887 phandle_name);
888 return;
889 }
890 } else {
891 pr_debug("Unable to find %s\n", phandle_name);
892 return;
893 }
894
895 if (add_opp(&l3_clk, device_list, count))
896 pr_err("Failed to add OPP levels for %s\n", phandle_name);
897
898 kfree(device_list);
899}
900
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800901static void populate_opp_table(struct platform_device *pdev)
902{
903 int cpu;
904 struct device *cpu_dev;
905 struct clk_osm *c, *parent;
906 struct clk_hw *hw_parent;
Deepak Katragaddaeda782e2017-10-12 11:06:28 -0700907 struct device_node *np = pdev->dev.of_node;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800908
909 for_each_possible_cpu(cpu) {
910 c = logical_cpu_to_clk(cpu);
911 if (!c) {
912 pr_err("no clock device for CPU=%d\n", cpu);
913 return;
914 }
915
916 hw_parent = clk_hw_get_parent(&c->hw);
917 parent = to_clk_osm(hw_parent);
918 cpu_dev = get_cpu_device(cpu);
919 if (cpu_dev)
Deepak Katragaddaeda782e2017-10-12 11:06:28 -0700920 if (add_opp(parent, &cpu_dev, 1))
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800921 pr_err("Failed to add OPP levels for %s\n",
922 dev_name(cpu_dev));
923 }
924
Deepak Katragaddaeda782e2017-10-12 11:06:28 -0700925 populate_l3_opp_table(np, "l3-devs");
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800926}
927
928static u64 clk_osm_get_cpu_cycle_counter(int cpu)
929{
930 u32 val;
Deepak Katragaddafc6bd3c2017-05-12 12:03:49 -0700931 int core_num;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800932 unsigned long flags;
Deepak Katragaddad9a67e92017-05-26 10:20:21 -0700933 u64 cycle_counter_ret;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800934 struct clk_osm *parent, *c = logical_cpu_to_clk(cpu);
935
936 if (IS_ERR_OR_NULL(c)) {
937 pr_err("no clock device for CPU=%d\n", cpu);
938 return 0;
939 }
940
941 parent = to_clk_osm(clk_hw_get_parent(&c->hw));
942
943 spin_lock_irqsave(&parent->lock, flags);
Deepak Katragaddaa83ccfe2017-04-11 15:57:11 -0700944 /*
945 * Use core 0's copy as proxy for the whole cluster when per
946 * core DCVS is disabled.
947 */
Deepak Katragaddafc6bd3c2017-05-12 12:03:49 -0700948 core_num = parent->per_core_dcvs ? c->core_num : 0;
949 val = clk_osm_read_reg_no_log(parent,
Odelu Kukatla3799c7c2017-08-20 20:48:45 +0530950 OSM_CYCLE_COUNTER_STATUS_REG(core_num, is_sdm845v1));
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800951
952 if (val < c->prev_cycle_counter) {
953 /* Handle counter overflow */
954 c->total_cycle_counter += UINT_MAX -
955 c->prev_cycle_counter + val;
956 c->prev_cycle_counter = val;
957 } else {
958 c->total_cycle_counter += val - c->prev_cycle_counter;
959 c->prev_cycle_counter = val;
960 }
Deepak Katragaddad9a67e92017-05-26 10:20:21 -0700961 cycle_counter_ret = c->total_cycle_counter;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800962 spin_unlock_irqrestore(&parent->lock, flags);
963
Deepak Katragaddad9a67e92017-05-26 10:20:21 -0700964 return cycle_counter_ret;
Deepak Katragadda7abd9312016-12-21 14:18:00 -0800965}
966
Deepak Katragadda8ee6b5b82017-07-24 16:47:10 -0700967static int clk_osm_read_lut(struct platform_device *pdev, struct clk_osm *c)
968{
969 u32 data, src, lval, i, j = OSM_TABLE_SIZE;
Deepak Katragadda02617bd2017-11-10 16:03:43 -0800970 struct clk_vdd_class *vdd = osm_clks_init[c->cluster_num].vdd_class;
Deepak Katragadda8ee6b5b82017-07-24 16:47:10 -0700971
972 for (i = 0; i < OSM_TABLE_SIZE; i++) {
973 data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE);
974 src = ((data & GENMASK(31, 30)) >> 30);
975 lval = (data & GENMASK(7, 0));
Deepak Katragadda9c360882017-11-21 17:17:54 -0800976 c->osm_table[i].ccount = CORE_COUNT_VAL(data);
Deepak Katragadda8ee6b5b82017-07-24 16:47:10 -0700977
978 if (!src)
979 c->osm_table[i].frequency = OSM_INIT_RATE;
980 else
981 c->osm_table[i].frequency = XO_RATE * lval;
982
983 data = clk_osm_read_reg(c, VOLT_REG + i * OSM_REG_SIZE);
984 c->osm_table[i].virtual_corner =
985 ((data & GENMASK(21, 16)) >> 16);
986 c->osm_table[i].open_loop_volt = (data & GENMASK(11, 0));
987
988 pr_debug("index=%d freq=%ld virtual_corner=%d open_loop_voltage=%u\n",
989 i, c->osm_table[i].frequency,
990 c->osm_table[i].virtual_corner,
991 c->osm_table[i].open_loop_volt);
992
Deepak Katragadda9c360882017-11-21 17:17:54 -0800993 if (i > 0 && j == OSM_TABLE_SIZE &&
994 c->osm_table[i].frequency ==
995 c->osm_table[i - 1].frequency &&
996 c->osm_table[i].ccount == c->osm_table[i - 1].ccount)
Deepak Katragadda8ee6b5b82017-07-24 16:47:10 -0700997 j = i;
998 }
999
1000 osm_clks_init[c->cluster_num].rate_max = devm_kcalloc(&pdev->dev,
1001 j, sizeof(unsigned long),
1002 GFP_KERNEL);
1003 if (!osm_clks_init[c->cluster_num].rate_max)
1004 return -ENOMEM;
1005
Deepak Katragadda02617bd2017-11-10 16:03:43 -08001006 if (vdd) {
1007 vdd->level_votes = devm_kcalloc(&pdev->dev, j,
1008 sizeof(*vdd->level_votes), GFP_KERNEL);
1009 if (!vdd->level_votes)
1010 return -ENOMEM;
1011
1012 vdd->vdd_uv = devm_kcalloc(&pdev->dev, j, sizeof(*vdd->vdd_uv),
1013 GFP_KERNEL);
1014 if (!vdd->vdd_uv)
1015 return -ENOMEM;
1016
1017 for (i = 0; i < j; i++) {
David Collins1e048402017-11-29 15:43:09 -08001018 if (c->osm_table[i].frequency < c->mx_turbo_freq)
Deepak Katragadda02617bd2017-11-10 16:03:43 -08001019 vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_NOM;
1020 else
1021 vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_TURBO;
1022 }
1023 vdd->num_levels = j;
1024 vdd->cur_level = j;
1025 vdd->use_max_uV = true;
1026 }
1027
Deepak Katragadda8ee6b5b82017-07-24 16:47:10 -07001028 for (i = 0; i < j; i++)
1029 osm_clks_init[c->cluster_num].rate_max[i] =
1030 c->osm_table[i].frequency;
1031
1032 c->num_entries = osm_clks_init[c->cluster_num].num_rate_max = j;
1033 return 0;
1034}
1035
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001036static int clk_osm_resources_init(struct platform_device *pdev)
1037{
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001038 struct resource *res;
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001039
1040 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1041 "osm_l3_base");
1042 if (!res) {
1043 dev_err(&pdev->dev,
1044 "Unable to get platform resource for osm_l3_base");
1045 return -ENOMEM;
1046 }
1047
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001048 l3_clk.pbase = (unsigned long)res->start;
1049 l3_clk.vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001050
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001051 if (!l3_clk.vbase) {
Osvaldo Banuelosa64c40a2017-03-20 16:01:45 -07001052 dev_err(&pdev->dev, "Unable to map osm_l3_base base\n");
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001053 return -ENOMEM;
1054 }
1055
1056 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1057 "osm_pwrcl_base");
1058 if (!res) {
1059 dev_err(&pdev->dev,
1060 "Unable to get platform resource for osm_pwrcl_base");
1061 return -ENOMEM;
1062 }
1063
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001064 pwrcl_clk.pbase = (unsigned long)res->start;
1065 pwrcl_clk.vbase = devm_ioremap(&pdev->dev, res->start,
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001066 resource_size(res));
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001067 if (!pwrcl_clk.vbase) {
Osvaldo Banuelosa64c40a2017-03-20 16:01:45 -07001068 dev_err(&pdev->dev, "Unable to map osm_pwrcl_base base\n");
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001069 return -ENOMEM;
1070 }
1071
1072 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1073 "osm_perfcl_base");
1074 if (!res) {
1075 dev_err(&pdev->dev,
1076 "Unable to get platform resource for osm_perfcl_base");
1077 return -ENOMEM;
1078 }
1079
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001080 perfcl_clk.pbase = (unsigned long)res->start;
1081 perfcl_clk.vbase = devm_ioremap(&pdev->dev, res->start,
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001082 resource_size(res));
1083
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001084 if (!perfcl_clk.vbase) {
Osvaldo Banuelosa64c40a2017-03-20 16:01:45 -07001085 dev_err(&pdev->dev, "Unable to map osm_perfcl_base base\n");
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001086 return -ENOMEM;
1087 }
1088
Osvaldo Banuelosa64c40a2017-03-20 16:01:45 -07001089 return 0;
1090}
1091
Odelu Kukatla3799c7c2017-08-20 20:48:45 +05301092static void clk_cpu_osm_driver_sdm670_fixup(void)
1093{
1094 osm_qcom_clk_hws[CPU4_PERFCL_CLK] = NULL;
1095 osm_qcom_clk_hws[CPU5_PERFCL_CLK] = NULL;
1096 osm_qcom_clk_hws[CPU4_PWRCL_CLK] = &cpu4_pwrcl_clk.hw;
1097 osm_qcom_clk_hws[CPU5_PWRCL_CLK] = &cpu5_pwrcl_clk.hw;
1098
1099 clk_cpu_map[4] = &cpu4_pwrcl_clk;
1100 clk_cpu_map[5] = &cpu5_pwrcl_clk;
1101
1102 cpu6_perfcl_clk.core_num = 0;
1103 cpu7_perfcl_clk.core_num = 1;
1104
1105 pwrcl_clk.max_core_count = 6;
1106 perfcl_clk.max_core_count = 2;
1107}
1108
David Collins1e048402017-11-29 15:43:09 -08001109/* Request MX supply if configured in device tree */
1110static int clk_cpu_osm_request_mx_supply(struct device *dev)
1111{
1112 u32 *array;
1113 int rc;
1114
1115 if (!of_find_property(dev->of_node, "qcom,mx-turbo-freq", NULL)) {
1116 osm_clks_init[l3_clk.cluster_num].vdd_class = NULL;
1117 osm_clks_init[pwrcl_clk.cluster_num].vdd_class = NULL;
1118 return 0;
1119 }
1120
1121 vdd_l3_mx_ao.regulator[0] = devm_regulator_get(dev, "vdd_l3_mx_ao");
1122 if (IS_ERR(vdd_l3_mx_ao.regulator[0])) {
1123 rc = PTR_ERR(vdd_l3_mx_ao.regulator[0]);
1124 if (rc != -EPROBE_DEFER)
1125 dev_err(dev, "Unable to get vdd_l3_mx_ao regulator, rc=%d\n",
1126 rc);
1127 return rc;
1128 }
1129
1130 vdd_pwrcl_mx_ao.regulator[0] = devm_regulator_get(dev,
1131 "vdd_pwrcl_mx_ao");
1132 if (IS_ERR(vdd_pwrcl_mx_ao.regulator[0])) {
1133 rc = PTR_ERR(vdd_pwrcl_mx_ao.regulator[0]);
1134 if (rc != -EPROBE_DEFER)
1135 dev_err(dev, "Unable to get vdd_pwrcl_mx_ao regulator, rc=%d\n",
1136 rc);
1137 return rc;
1138 }
1139
1140 array = kcalloc(MAX_CLUSTER_CNT, sizeof(*array), GFP_KERNEL);
1141 if (!array)
1142 return -ENOMEM;
1143
1144 rc = of_property_read_u32_array(dev->of_node, "qcom,mx-turbo-freq",
1145 array, MAX_CLUSTER_CNT);
1146 if (rc) {
1147 dev_err(dev, "unable to read qcom,mx-turbo-freq property, rc=%d\n",
1148 rc);
1149 kfree(array);
1150 return rc;
1151 }
1152
1153 l3_clk.mx_turbo_freq = array[l3_clk.cluster_num];
1154 pwrcl_clk.mx_turbo_freq = array[pwrcl_clk.cluster_num];
1155 perfcl_clk.mx_turbo_freq = array[perfcl_clk.cluster_num];
1156
1157 kfree(array);
1158
1159 return 0;
1160}
1161
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001162static int clk_cpu_osm_driver_probe(struct platform_device *pdev)
1163{
Deepak Katragadda02617bd2017-11-10 16:03:43 -08001164 int rc = 0, i, cpu;
David Collins1e048402017-11-29 15:43:09 -08001165 u32 val;
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001166 int num_clks = ARRAY_SIZE(osm_qcom_clk_hws);
1167 struct clk *ext_xo_clk, *clk;
Deepak Katragadda02617bd2017-11-10 16:03:43 -08001168 struct clk_osm *osm_clk;
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001169 struct device *dev = &pdev->dev;
1170 struct clk_onecell_data *clk_data;
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001171 struct cpu_cycle_counter_cb cb = {
1172 .get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter,
1173 };
1174
1175 /*
1176 * Require the RPM-XO clock to be registered before OSM.
1177 * The cpuss_gpll0_clk_src is listed to be configured by BL.
1178 */
1179 ext_xo_clk = devm_clk_get(dev, "xo_ao");
1180 if (IS_ERR(ext_xo_clk)) {
1181 if (PTR_ERR(ext_xo_clk) != -EPROBE_DEFER)
1182 dev_err(dev, "Unable to get xo clock\n");
1183 return PTR_ERR(ext_xo_clk);
1184 }
1185
Odelu Kukatla3799c7c2017-08-20 20:48:45 +05301186 is_sdm845v1 = of_device_is_compatible(pdev->dev.of_node,
1187 "qcom,clk-cpu-osm");
1188
1189 if (of_device_is_compatible(pdev->dev.of_node,
David Collins1e048402017-11-29 15:43:09 -08001190 "qcom,clk-cpu-osm-sdm670"))
Odelu Kukatla3799c7c2017-08-20 20:48:45 +05301191 clk_cpu_osm_driver_sdm670_fixup();
Deepak Katragadda02617bd2017-11-10 16:03:43 -08001192
David Collins1e048402017-11-29 15:43:09 -08001193 rc = clk_cpu_osm_request_mx_supply(dev);
1194 if (rc)
Deepak Katragadda02617bd2017-11-10 16:03:43 -08001195 return rc;
Deepak Katragaddafc6bd3c2017-05-12 12:03:49 -07001196
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001197 clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
1198 GFP_KERNEL);
1199 if (!clk_data)
1200 goto exit;
1201
1202 clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks *
1203 sizeof(struct clk *)), GFP_KERNEL);
1204 if (!clk_data->clks)
1205 goto clk_err;
1206
1207 clk_data->clk_num = num_clks;
1208
Deepak Katragadda4e2e1dc2017-07-25 14:41:52 -07001209 rc = clk_osm_resources_init(pdev);
1210 if (rc) {
1211 if (rc != -EPROBE_DEFER)
1212 dev_err(&pdev->dev, "OSM resources init failed, rc=%d\n",
1213 rc);
1214 return rc;
1215 }
1216
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001217 /* Check if per-core DCVS is enabled/not */
1218 val = clk_osm_read_reg(&pwrcl_clk, CORE_DCVS_CTRL);
Amit Nischal79c1dc22017-11-27 16:21:35 +05301219 if (val & BIT(0))
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001220 pwrcl_clk.per_core_dcvs = true;
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001221
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001222 val = clk_osm_read_reg(&perfcl_clk, CORE_DCVS_CTRL);
Amit Nischal79c1dc22017-11-27 16:21:35 +05301223 if (val & BIT(0))
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001224 perfcl_clk.per_core_dcvs = true;
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001225
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001226 rc = clk_osm_read_lut(pdev, &l3_clk);
1227 if (rc) {
1228 dev_err(&pdev->dev, "Unable to read OSM LUT for L3, rc=%d\n",
1229 rc);
1230 return rc;
1231 }
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001232
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001233 rc = clk_osm_read_lut(pdev, &pwrcl_clk);
1234 if (rc) {
1235 dev_err(&pdev->dev, "Unable to read OSM LUT for power cluster, rc=%d\n",
1236 rc);
1237 return rc;
1238 }
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001239
Deepak Katragaddacc3e9472017-07-07 10:30:15 -07001240 rc = clk_osm_read_lut(pdev, &perfcl_clk);
1241 if (rc) {
1242 dev_err(&pdev->dev, "Unable to read OSM LUT for perf cluster, rc=%d\n",
1243 rc);
1244 return rc;
Osvaldo Banuelosa64c40a2017-03-20 16:01:45 -07001245 }
1246
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001247 spin_lock_init(&l3_clk.lock);
1248 spin_lock_init(&pwrcl_clk.lock);
1249 spin_lock_init(&perfcl_clk.lock);
1250
1251 /* Register OSM l3, pwr and perf clocks with Clock Framework */
1252 for (i = 0; i < num_clks; i++) {
Odelu Kukatla3799c7c2017-08-20 20:48:45 +05301253 if (!osm_qcom_clk_hws[i])
1254 continue;
1255
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001256 clk = devm_clk_register(&pdev->dev, osm_qcom_clk_hws[i]);
1257 if (IS_ERR(clk)) {
1258 dev_err(&pdev->dev, "Unable to register CPU clock at index %d\n",
1259 i);
1260 return PTR_ERR(clk);
1261 }
1262 clk_data->clks[i] = clk;
1263 }
1264
1265 rc = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get,
1266 clk_data);
1267 if (rc) {
1268 dev_err(&pdev->dev, "Unable to register CPU clocks\n");
1269 goto provider_err;
1270 }
1271
1272 get_online_cpus();
1273
Deepak Katragadda4280f412017-07-24 13:28:26 -07001274 WARN(clk_prepare_enable(l3_cluster0_vote_clk.hw.clk),
Deepak Katragadda8ee6b5b82017-07-24 16:47:10 -07001275 "clk: Failed to enable cluster0 clock for L3\n");
Deepak Katragadda4280f412017-07-24 13:28:26 -07001276 WARN(clk_prepare_enable(l3_cluster1_vote_clk.hw.clk),
Deepak Katragadda8ee6b5b82017-07-24 16:47:10 -07001277 "clk: Failed to enable cluster1 clock for L3\n");
Deepak Katragadda43db9372017-10-12 10:55:55 -07001278 WARN(clk_prepare_enable(l3_misc_vote_clk.hw.clk),
1279 "clk: Failed to enable misc clock for L3\n");
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001280
Deepak Katragadda02617bd2017-11-10 16:03:43 -08001281 /*
1282 * Call clk_prepare_enable for the silver clock explicitly in order to
1283 * place an implicit vote on MX
1284 */
1285 for_each_online_cpu(cpu) {
1286 osm_clk = logical_cpu_to_clk(cpu);
1287 if (!osm_clk)
1288 return -EINVAL;
1289 clk_prepare_enable(osm_clk->hw.clk);
1290 }
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001291 populate_opp_table(pdev);
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001292
1293 of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
1294 register_cpu_cycle_counter_cb(&cb);
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001295 put_online_cpus();
1296
Stephen Boyd0c29ef62017-05-05 10:41:22 -07001297 rc = cpufreq_register_driver(&qcom_osm_cpufreq_driver);
1298 if (rc)
1299 goto provider_err;
1300
1301 pr_info("OSM CPUFreq driver inited\n");
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001302 return 0;
Stephen Boyd0c29ef62017-05-05 10:41:22 -07001303
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001304provider_err:
1305 if (clk_data)
1306 devm_kfree(&pdev->dev, clk_data->clks);
1307clk_err:
1308 devm_kfree(&pdev->dev, clk_data);
1309exit:
Stephen Boyd0c29ef62017-05-05 10:41:22 -07001310 dev_err(&pdev->dev, "OSM CPUFreq driver failed to initialize, rc=%d\n",
1311 rc);
1312 panic("Unable to Setup OSM CPUFreq");
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001313}
1314
1315static const struct of_device_id match_table[] = {
1316 { .compatible = "qcom,clk-cpu-osm" },
Deepak Katragaddafc6bd3c2017-05-12 12:03:49 -07001317 { .compatible = "qcom,clk-cpu-osm-v2" },
Odelu Kukatla3799c7c2017-08-20 20:48:45 +05301318 { .compatible = "qcom,clk-cpu-osm-sdm670" },
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001319 {}
1320};
1321
1322static struct platform_driver clk_cpu_osm_driver = {
1323 .probe = clk_cpu_osm_driver_probe,
1324 .driver = {
1325 .name = "clk-cpu-osm",
1326 .of_match_table = match_table,
1327 .owner = THIS_MODULE,
1328 },
1329};
1330
1331static int __init clk_cpu_osm_init(void)
1332{
1333 return platform_driver_register(&clk_cpu_osm_driver);
1334}
Deepak Katragaddaef44e102017-06-21 10:30:46 -07001335subsys_initcall(clk_cpu_osm_init);
Deepak Katragadda7abd9312016-12-21 14:18:00 -08001336
1337static void __exit clk_cpu_osm_exit(void)
1338{
1339 platform_driver_unregister(&clk_cpu_osm_driver);
1340}
1341module_exit(clk_cpu_osm_exit);
1342
1343MODULE_DESCRIPTION("QTI CPU clock driver for OSM");
1344MODULE_LICENSE("GPL v2");