18
18
#define CLK_RPMH_ARC_EN_OFFSET 0
19
19
#define CLK_RPMH_VRM_EN_OFFSET 4
20
20
21
+ #define BCM_TCS_CMD_COMMIT_MASK 0x40000000
22
+ #define BCM_TCS_CMD_VALID_SHIFT 29
23
+ #define BCM_TCS_CMD_VOTE_MASK 0x3fff
24
+ #define BCM_TCS_CMD_VOTE_SHIFT 0
25
+
26
+ #define BCM_TCS_CMD (valid , vote ) \
27
+ (BCM_TCS_CMD_COMMIT_MASK | \
28
+ ((valid) << BCM_TCS_CMD_VALID_SHIFT) | \
29
+ ((vote & BCM_TCS_CMD_VOTE_MASK) \
30
+ << BCM_TCS_CMD_VOTE_SHIFT))
31
+
32
+ /**
33
+ * struct bcm_db - Auxiliary data pertaining to each Bus Clock Manager(BCM)
34
+ * @unit: divisor used to convert Hz value to an RPMh msg
35
+ * @width: multiplier used to convert Hz value to an RPMh msg
36
+ * @vcd: virtual clock domain that this bcm belongs to
37
+ * @reserved: reserved to pad the struct
38
+ */
39
+ struct bcm_db {
40
+ __le32 unit ;
41
+ __le16 width ;
42
+ u8 vcd ;
43
+ u8 reserved ;
44
+ };
45
+
21
46
/**
22
47
* struct clk_rpmh - individual rpmh clock data structure
23
48
* @hw: handle between common and hardware-specific interfaces
29
54
* @aggr_state: rpmh clock aggregated state
30
55
* @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh
31
56
* @valid_state_mask: mask to determine the state of the rpmh clock
57
+ * @unit: divisor to convert rate to rpmh msg in magnitudes of Khz
32
58
* @dev: device to which it is attached
33
59
* @peer: pointer to the clock rpmh sibling
34
60
*/
@@ -42,6 +68,7 @@ struct clk_rpmh {
42
68
u32 aggr_state ;
43
69
u32 last_sent_aggr_state ;
44
70
u32 valid_state_mask ;
71
+ u32 unit ;
45
72
struct device * dev ;
46
73
struct clk_rpmh * peer ;
47
74
};
@@ -98,6 +125,17 @@ static DEFINE_MUTEX(rpmh_clk_lock);
98
125
__DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \
99
126
CLK_RPMH_VRM_EN_OFFSET, 1, _div)
100
127
128
+ #define DEFINE_CLK_RPMH_BCM (_platform , _name , _res_name ) \
129
+ static struct clk_rpmh _platform##_##_name = { \
130
+ .res_name = _res_name, \
131
+ .valid_state_mask = BIT(RPMH_ACTIVE_ONLY_STATE), \
132
+ .div = 1, \
133
+ .hw.init = &(struct clk_init_data){ \
134
+ .ops = &clk_rpmh_bcm_ops, \
135
+ .name = #_name, \
136
+ }, \
137
+ }
138
+
101
139
static inline struct clk_rpmh * to_clk_rpmh (struct clk_hw * _hw )
102
140
{
103
141
return container_of (_hw , struct clk_rpmh , hw );
@@ -210,13 +248,104 @@ static const struct clk_ops clk_rpmh_ops = {
210
248
.recalc_rate = clk_rpmh_recalc_rate ,
211
249
};
212
250
251
+ static int clk_rpmh_bcm_send_cmd (struct clk_rpmh * c , bool enable )
252
+ {
253
+ struct tcs_cmd cmd = { 0 };
254
+ u32 cmd_state ;
255
+ int ret ;
256
+
257
+ mutex_lock (& rpmh_clk_lock );
258
+
259
+ cmd_state = 0 ;
260
+ if (enable ) {
261
+ cmd_state = 1 ;
262
+ if (c -> aggr_state )
263
+ cmd_state = c -> aggr_state ;
264
+ }
265
+
266
+ if (c -> last_sent_aggr_state == cmd_state ) {
267
+ mutex_unlock (& rpmh_clk_lock );
268
+ return 0 ;
269
+ }
270
+
271
+ cmd .addr = c -> res_addr ;
272
+ cmd .data = BCM_TCS_CMD (enable , cmd_state );
273
+
274
+ ret = rpmh_write_async (c -> dev , RPMH_ACTIVE_ONLY_STATE , & cmd , 1 );
275
+ if (ret ) {
276
+ dev_err (c -> dev , "set active state of %s failed: (%d)\n" ,
277
+ c -> res_name , ret );
278
+ mutex_unlock (& rpmh_clk_lock );
279
+ return ret ;
280
+ }
281
+
282
+ c -> last_sent_aggr_state = cmd_state ;
283
+
284
+ mutex_unlock (& rpmh_clk_lock );
285
+
286
+ return 0 ;
287
+ }
288
+
289
+ static int clk_rpmh_bcm_prepare (struct clk_hw * hw )
290
+ {
291
+ struct clk_rpmh * c = to_clk_rpmh (hw );
292
+
293
+ return clk_rpmh_bcm_send_cmd (c , true);
294
+ };
295
+
296
+ static void clk_rpmh_bcm_unprepare (struct clk_hw * hw )
297
+ {
298
+ struct clk_rpmh * c = to_clk_rpmh (hw );
299
+
300
+ clk_rpmh_bcm_send_cmd (c , false);
301
+ };
302
+
303
+ static int clk_rpmh_bcm_set_rate (struct clk_hw * hw , unsigned long rate ,
304
+ unsigned long parent_rate )
305
+ {
306
+ struct clk_rpmh * c = to_clk_rpmh (hw );
307
+
308
+ c -> aggr_state = rate / c -> unit ;
309
+ /*
310
+ * Since any non-zero value sent to hw would result in enabling the
311
+ * clock, only send the value if the clock has already been prepared.
312
+ */
313
+ if (clk_hw_is_prepared (hw ))
314
+ clk_rpmh_bcm_send_cmd (c , true);
315
+
316
+ return 0 ;
317
+ };
318
+
319
+ static long clk_rpmh_round_rate (struct clk_hw * hw , unsigned long rate ,
320
+ unsigned long * parent_rate )
321
+ {
322
+ return rate ;
323
+ }
324
+
325
+ static unsigned long clk_rpmh_bcm_recalc_rate (struct clk_hw * hw ,
326
+ unsigned long prate )
327
+ {
328
+ struct clk_rpmh * c = to_clk_rpmh (hw );
329
+
330
+ return c -> aggr_state * c -> unit ;
331
+ }
332
+
333
+ static const struct clk_ops clk_rpmh_bcm_ops = {
334
+ .prepare = clk_rpmh_bcm_prepare ,
335
+ .unprepare = clk_rpmh_bcm_unprepare ,
336
+ .set_rate = clk_rpmh_bcm_set_rate ,
337
+ .round_rate = clk_rpmh_round_rate ,
338
+ .recalc_rate = clk_rpmh_bcm_recalc_rate ,
339
+ };
340
+
213
341
/* Resource name must match resource id present in cmd-db. */
214
342
DEFINE_CLK_RPMH_ARC (sdm845 , bi_tcxo , bi_tcxo_ao , "xo.lvl" , 0x3 , 2 );
215
343
DEFINE_CLK_RPMH_VRM (sdm845 , ln_bb_clk2 , ln_bb_clk2_ao , "lnbclka2" , 2 );
216
344
DEFINE_CLK_RPMH_VRM (sdm845 , ln_bb_clk3 , ln_bb_clk3_ao , "lnbclka3" , 2 );
217
345
DEFINE_CLK_RPMH_VRM (sdm845 , rf_clk1 , rf_clk1_ao , "rfclka1" , 1 );
218
346
DEFINE_CLK_RPMH_VRM (sdm845 , rf_clk2 , rf_clk2_ao , "rfclka2" , 1 );
219
347
DEFINE_CLK_RPMH_VRM (sdm845 , rf_clk3 , rf_clk3_ao , "rfclka3" , 1 );
348
+ DEFINE_CLK_RPMH_BCM (sdm845 , ipa , "IP0" );
220
349
221
350
static struct clk_hw * sdm845_rpmh_clocks [] = {
222
351
[RPMH_CXO_CLK ] = & sdm845_bi_tcxo .hw ,
@@ -231,6 +360,7 @@ static struct clk_hw *sdm845_rpmh_clocks[] = {
231
360
[RPMH_RF_CLK2_A ] = & sdm845_rf_clk2_ao .hw ,
232
361
[RPMH_RF_CLK3 ] = & sdm845_rf_clk3 .hw ,
233
362
[RPMH_RF_CLK3_A ] = & sdm845_rf_clk3_ao .hw ,
363
+ [RPMH_IPA_CLK ] = & sdm845_ipa .hw ,
234
364
};
235
365
236
366
static const struct clk_rpmh_desc clk_rpmh_sdm845 = {
@@ -267,6 +397,8 @@ static int clk_rpmh_probe(struct platform_device *pdev)
267
397
268
398
for (i = 0 ; i < desc -> num_clks ; i ++ ) {
269
399
u32 res_addr ;
400
+ size_t aux_data_len ;
401
+ const struct bcm_db * data ;
270
402
271
403
rpmh_clk = to_clk_rpmh (hw_clks [i ]);
272
404
res_addr = cmd_db_read_addr (rpmh_clk -> res_name );
@@ -275,6 +407,20 @@ static int clk_rpmh_probe(struct platform_device *pdev)
275
407
rpmh_clk -> res_name );
276
408
return - ENODEV ;
277
409
}
410
+
411
+ data = cmd_db_read_aux_data (rpmh_clk -> res_name , & aux_data_len );
412
+ if (IS_ERR (data )) {
413
+ ret = PTR_ERR (data );
414
+ dev_err (& pdev -> dev ,
415
+ "error reading RPMh aux data for %s (%d)\n" ,
416
+ rpmh_clk -> res_name , ret );
417
+ return ret ;
418
+ }
419
+
420
+ /* Convert unit from Khz to Hz */
421
+ if (aux_data_len == sizeof (* data ))
422
+ rpmh_clk -> unit = le32_to_cpu (data -> unit ) * 1000ULL ;
423
+
278
424
rpmh_clk -> res_addr += res_addr ;
279
425
rpmh_clk -> dev = & pdev -> dev ;
280
426
0 commit comments