34
34
/* Internal sampling clock frequency */
35
35
#define HW_TIMER_HZ 19200000
36
36
37
- #define BWMON_V4_GLOBAL_IRQ_CLEAR 0x008
38
- #define BWMON_V4_GLOBAL_IRQ_ENABLE 0x00c
37
+ #define BWMON_V4_GLOBAL_IRQ_CLEAR 0x108
38
+ #define BWMON_V4_GLOBAL_IRQ_ENABLE 0x10c
39
39
/*
40
40
* All values here and further are matching regmap fields, so without absolute
41
41
* register offsets.
42
42
*/
43
43
#define BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE BIT(0)
44
44
45
+ /*
46
+ * Starting with SDM845, the BWMON4 register space has changed a bit:
47
+ * the global registers were jammed into the beginning of the monitor region.
48
+ * To keep the proper offsets, one would have to map <GLOBAL_BASE 0x200> and
49
+ * <GLOBAL_BASE+0x100 0x300>, which is straight up wrong.
50
+ * To facilitate for that, while allowing the older, arguably more proper
51
+ * implementations to work, offset the global registers by -0x100 to avoid
52
+ * having to map half of the global registers twice.
53
+ */
54
+ #define BWMON_V4_845_OFFSET 0x100
55
+ #define BWMON_V4_GLOBAL_IRQ_CLEAR_845 (BWMON_V4_GLOBAL_IRQ_CLEAR - BWMON_V4_845_OFFSET)
56
+ #define BWMON_V4_GLOBAL_IRQ_ENABLE_845 (BWMON_V4_GLOBAL_IRQ_ENABLE - BWMON_V4_845_OFFSET)
57
+
45
58
#define BWMON_V4_IRQ_STATUS 0x100
46
59
#define BWMON_V4_IRQ_CLEAR 0x108
47
60
118
131
#define BWMON_NEEDS_FORCE_CLEAR BIT(1)
119
132
120
133
enum bwmon_fields {
134
+ /* Global region fields, keep them at the top */
121
135
F_GLOBAL_IRQ_CLEAR ,
122
136
F_GLOBAL_IRQ_ENABLE ,
123
- F_IRQ_STATUS ,
137
+ F_NUM_GLOBAL_FIELDS ,
138
+
139
+ /* Monitor region fields */
140
+ F_IRQ_STATUS = F_NUM_GLOBAL_FIELDS ,
124
141
F_IRQ_CLEAR ,
125
142
F_IRQ_ENABLE ,
126
143
F_ENABLE ,
@@ -157,6 +174,9 @@ struct icc_bwmon_data {
157
174
158
175
const struct regmap_config * regmap_cfg ;
159
176
const struct reg_field * regmap_fields ;
177
+
178
+ const struct regmap_config * global_regmap_cfg ;
179
+ const struct reg_field * global_regmap_fields ;
160
180
};
161
181
162
182
struct icc_bwmon {
@@ -165,6 +185,7 @@ struct icc_bwmon {
165
185
int irq ;
166
186
167
187
struct regmap_field * regs [F_NUM_FIELDS ];
188
+ struct regmap_field * global_regs [F_NUM_GLOBAL_FIELDS ];
168
189
169
190
unsigned int max_bw_kbps ;
170
191
unsigned int min_bw_kbps ;
@@ -174,8 +195,8 @@ struct icc_bwmon {
174
195
175
196
/* BWMON v4 */
176
197
static const struct reg_field msm8998_bwmon_reg_fields [] = {
177
- [F_GLOBAL_IRQ_CLEAR ] = REG_FIELD ( BWMON_V4_GLOBAL_IRQ_CLEAR , 0 , 0 ) ,
178
- [F_GLOBAL_IRQ_ENABLE ] = REG_FIELD ( BWMON_V4_GLOBAL_IRQ_ENABLE , 0 , 0 ) ,
198
+ [F_GLOBAL_IRQ_CLEAR ] = {} ,
199
+ [F_GLOBAL_IRQ_ENABLE ] = {} ,
179
200
[F_IRQ_STATUS ] = REG_FIELD (BWMON_V4_IRQ_STATUS , 4 , 7 ),
180
201
[F_IRQ_CLEAR ] = REG_FIELD (BWMON_V4_IRQ_CLEAR , 4 , 7 ),
181
202
[F_IRQ_ENABLE ] = REG_FIELD (BWMON_V4_IRQ_ENABLE , 4 , 7 ),
@@ -201,7 +222,6 @@ static const struct reg_field msm8998_bwmon_reg_fields[] = {
201
222
};
202
223
203
224
static const struct regmap_range msm8998_bwmon_reg_noread_ranges [] = {
204
- regmap_reg_range (BWMON_V4_GLOBAL_IRQ_CLEAR , BWMON_V4_GLOBAL_IRQ_CLEAR ),
205
225
regmap_reg_range (BWMON_V4_IRQ_CLEAR , BWMON_V4_IRQ_CLEAR ),
206
226
regmap_reg_range (BWMON_V4_CLEAR , BWMON_V4_CLEAR ),
207
227
};
@@ -221,16 +241,33 @@ static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = {
221
241
.n_yes_ranges = ARRAY_SIZE (msm8998_bwmon_reg_volatile_ranges ),
222
242
};
223
243
244
+ static const struct reg_field msm8998_bwmon_global_reg_fields [] = {
245
+ [F_GLOBAL_IRQ_CLEAR ] = REG_FIELD (BWMON_V4_GLOBAL_IRQ_CLEAR , 0 , 0 ),
246
+ [F_GLOBAL_IRQ_ENABLE ] = REG_FIELD (BWMON_V4_GLOBAL_IRQ_ENABLE , 0 , 0 ),
247
+ };
248
+
249
+ static const struct regmap_range msm8998_bwmon_global_reg_noread_ranges [] = {
250
+ regmap_reg_range (BWMON_V4_GLOBAL_IRQ_CLEAR , BWMON_V4_GLOBAL_IRQ_CLEAR ),
251
+ };
252
+
253
+ static const struct regmap_access_table msm8998_bwmon_global_reg_read_table = {
254
+ .no_ranges = msm8998_bwmon_global_reg_noread_ranges ,
255
+ .n_no_ranges = ARRAY_SIZE (msm8998_bwmon_global_reg_noread_ranges ),
256
+ };
257
+
224
258
/*
225
259
* Fill the cache for non-readable registers only as rest does not really
226
260
* matter and can be read from the device.
227
261
*/
228
262
static const struct reg_default msm8998_bwmon_reg_defaults [] = {
229
- { BWMON_V4_GLOBAL_IRQ_CLEAR , 0x0 },
230
263
{ BWMON_V4_IRQ_CLEAR , 0x0 },
231
264
{ BWMON_V4_CLEAR , 0x0 },
232
265
};
233
266
267
+ static const struct reg_default msm8998_bwmon_global_reg_defaults [] = {
268
+ { BWMON_V4_GLOBAL_IRQ_CLEAR , 0x0 },
269
+ };
270
+
234
271
static const struct regmap_config msm8998_bwmon_regmap_cfg = {
235
272
.reg_bits = 32 ,
236
273
.reg_stride = 4 ,
@@ -251,6 +288,93 @@ static const struct regmap_config msm8998_bwmon_regmap_cfg = {
251
288
.cache_type = REGCACHE_RBTREE ,
252
289
};
253
290
291
+ static const struct regmap_config msm8998_bwmon_global_regmap_cfg = {
292
+ .reg_bits = 32 ,
293
+ .reg_stride = 4 ,
294
+ .val_bits = 32 ,
295
+ /*
296
+ * No concurrent access expected - driver has one interrupt handler,
297
+ * regmap is not shared, no driver or user-space API.
298
+ */
299
+ .disable_locking = true,
300
+ .rd_table = & msm8998_bwmon_global_reg_read_table ,
301
+ .reg_defaults = msm8998_bwmon_global_reg_defaults ,
302
+ .num_reg_defaults = ARRAY_SIZE (msm8998_bwmon_global_reg_defaults ),
303
+ /*
304
+ * Cache is necessary for using regmap fields with non-readable
305
+ * registers.
306
+ */
307
+ .cache_type = REGCACHE_RBTREE ,
308
+ };
309
+
310
+ static const struct reg_field sdm845_cpu_bwmon_reg_fields [] = {
311
+ [F_GLOBAL_IRQ_CLEAR ] = REG_FIELD (BWMON_V4_GLOBAL_IRQ_CLEAR_845 , 0 , 0 ),
312
+ [F_GLOBAL_IRQ_ENABLE ] = REG_FIELD (BWMON_V4_GLOBAL_IRQ_ENABLE_845 , 0 , 0 ),
313
+ [F_IRQ_STATUS ] = REG_FIELD (BWMON_V4_IRQ_STATUS , 4 , 7 ),
314
+ [F_IRQ_CLEAR ] = REG_FIELD (BWMON_V4_IRQ_CLEAR , 4 , 7 ),
315
+ [F_IRQ_ENABLE ] = REG_FIELD (BWMON_V4_IRQ_ENABLE , 4 , 7 ),
316
+ /* F_ENABLE covers entire register to disable other features */
317
+ [F_ENABLE ] = REG_FIELD (BWMON_V4_ENABLE , 0 , 31 ),
318
+ [F_CLEAR ] = REG_FIELD (BWMON_V4_CLEAR , 0 , 1 ),
319
+ [F_SAMPLE_WINDOW ] = REG_FIELD (BWMON_V4_SAMPLE_WINDOW , 0 , 23 ),
320
+ [F_THRESHOLD_HIGH ] = REG_FIELD (BWMON_V4_THRESHOLD_HIGH , 0 , 11 ),
321
+ [F_THRESHOLD_MED ] = REG_FIELD (BWMON_V4_THRESHOLD_MED , 0 , 11 ),
322
+ [F_THRESHOLD_LOW ] = REG_FIELD (BWMON_V4_THRESHOLD_LOW , 0 , 11 ),
323
+ [F_ZONE_ACTIONS_ZONE0 ] = REG_FIELD (BWMON_V4_ZONE_ACTIONS , 0 , 7 ),
324
+ [F_ZONE_ACTIONS_ZONE1 ] = REG_FIELD (BWMON_V4_ZONE_ACTIONS , 8 , 15 ),
325
+ [F_ZONE_ACTIONS_ZONE2 ] = REG_FIELD (BWMON_V4_ZONE_ACTIONS , 16 , 23 ),
326
+ [F_ZONE_ACTIONS_ZONE3 ] = REG_FIELD (BWMON_V4_ZONE_ACTIONS , 24 , 31 ),
327
+ [F_THRESHOLD_COUNT_ZONE0 ] = REG_FIELD (BWMON_V4_THRESHOLD_COUNT , 0 , 7 ),
328
+ [F_THRESHOLD_COUNT_ZONE1 ] = REG_FIELD (BWMON_V4_THRESHOLD_COUNT , 8 , 15 ),
329
+ [F_THRESHOLD_COUNT_ZONE2 ] = REG_FIELD (BWMON_V4_THRESHOLD_COUNT , 16 , 23 ),
330
+ [F_THRESHOLD_COUNT_ZONE3 ] = REG_FIELD (BWMON_V4_THRESHOLD_COUNT , 24 , 31 ),
331
+ [F_ZONE0_MAX ] = REG_FIELD (BWMON_V4_ZONE_MAX (0 ), 0 , 11 ),
332
+ [F_ZONE1_MAX ] = REG_FIELD (BWMON_V4_ZONE_MAX (1 ), 0 , 11 ),
333
+ [F_ZONE2_MAX ] = REG_FIELD (BWMON_V4_ZONE_MAX (2 ), 0 , 11 ),
334
+ [F_ZONE3_MAX ] = REG_FIELD (BWMON_V4_ZONE_MAX (3 ), 0 , 11 ),
335
+ };
336
+
337
+ static const struct regmap_range sdm845_cpu_bwmon_reg_noread_ranges [] = {
338
+ regmap_reg_range (BWMON_V4_GLOBAL_IRQ_CLEAR_845 , BWMON_V4_GLOBAL_IRQ_CLEAR_845 ),
339
+ regmap_reg_range (BWMON_V4_IRQ_CLEAR , BWMON_V4_IRQ_CLEAR ),
340
+ regmap_reg_range (BWMON_V4_CLEAR , BWMON_V4_CLEAR ),
341
+ };
342
+
343
+ static const struct regmap_access_table sdm845_cpu_bwmon_reg_read_table = {
344
+ .no_ranges = sdm845_cpu_bwmon_reg_noread_ranges ,
345
+ .n_no_ranges = ARRAY_SIZE (sdm845_cpu_bwmon_reg_noread_ranges ),
346
+ };
347
+
348
+ /*
349
+ * Fill the cache for non-readable registers only as rest does not really
350
+ * matter and can be read from the device.
351
+ */
352
+ static const struct reg_default sdm845_cpu_bwmon_reg_defaults [] = {
353
+ { BWMON_V4_GLOBAL_IRQ_CLEAR_845 , 0x0 },
354
+ { BWMON_V4_IRQ_CLEAR , 0x0 },
355
+ { BWMON_V4_CLEAR , 0x0 },
356
+ };
357
+
358
+ static const struct regmap_config sdm845_cpu_bwmon_regmap_cfg = {
359
+ .reg_bits = 32 ,
360
+ .reg_stride = 4 ,
361
+ .val_bits = 32 ,
362
+ /*
363
+ * No concurrent access expected - driver has one interrupt handler,
364
+ * regmap is not shared, no driver or user-space API.
365
+ */
366
+ .disable_locking = true,
367
+ .rd_table = & sdm845_cpu_bwmon_reg_read_table ,
368
+ .volatile_table = & msm8998_bwmon_reg_volatile_table ,
369
+ .reg_defaults = sdm845_cpu_bwmon_reg_defaults ,
370
+ .num_reg_defaults = ARRAY_SIZE (sdm845_cpu_bwmon_reg_defaults ),
371
+ /*
372
+ * Cache is necessary for using regmap fields with non-readable
373
+ * registers.
374
+ */
375
+ .cache_type = REGCACHE_RBTREE ,
376
+ };
377
+
254
378
/* BWMON v5 */
255
379
static const struct reg_field sdm845_llcc_bwmon_reg_fields [] = {
256
380
[F_GLOBAL_IRQ_CLEAR ] = {},
@@ -349,6 +473,13 @@ static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all)
349
473
350
474
static void bwmon_clear_irq (struct icc_bwmon * bwmon )
351
475
{
476
+ struct regmap_field * global_irq_clr ;
477
+
478
+ if (bwmon -> data -> global_regmap_fields )
479
+ global_irq_clr = bwmon -> global_regs [F_GLOBAL_IRQ_CLEAR ];
480
+ else
481
+ global_irq_clr = bwmon -> regs [F_GLOBAL_IRQ_CLEAR ];
482
+
352
483
/*
353
484
* Clear zone and global interrupts. The order and barriers are
354
485
* important. Quoting downstream Qualcomm msm-4.9 tree:
@@ -369,15 +500,22 @@ static void bwmon_clear_irq(struct icc_bwmon *bwmon)
369
500
if (bwmon -> data -> quirks & BWMON_NEEDS_FORCE_CLEAR )
370
501
regmap_field_force_write (bwmon -> regs [F_IRQ_CLEAR ], 0 );
371
502
if (bwmon -> data -> quirks & BWMON_HAS_GLOBAL_IRQ )
372
- regmap_field_force_write (bwmon -> regs [ F_GLOBAL_IRQ_CLEAR ] ,
503
+ regmap_field_force_write (global_irq_clr ,
373
504
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE );
374
505
}
375
506
376
507
static void bwmon_disable (struct icc_bwmon * bwmon )
377
508
{
509
+ struct regmap_field * global_irq_en ;
510
+
511
+ if (bwmon -> data -> global_regmap_fields )
512
+ global_irq_en = bwmon -> global_regs [F_GLOBAL_IRQ_ENABLE ];
513
+ else
514
+ global_irq_en = bwmon -> regs [F_GLOBAL_IRQ_ENABLE ];
515
+
378
516
/* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
379
517
if (bwmon -> data -> quirks & BWMON_HAS_GLOBAL_IRQ )
380
- regmap_field_write (bwmon -> regs [ F_GLOBAL_IRQ_ENABLE ] , 0x0 );
518
+ regmap_field_write (global_irq_en , 0x0 );
381
519
regmap_field_write (bwmon -> regs [F_IRQ_ENABLE ], 0x0 );
382
520
383
521
/*
@@ -389,10 +527,18 @@ static void bwmon_disable(struct icc_bwmon *bwmon)
389
527
390
528
static void bwmon_enable (struct icc_bwmon * bwmon , unsigned int irq_enable )
391
529
{
530
+ struct regmap_field * global_irq_en ;
531
+
532
+ if (bwmon -> data -> global_regmap_fields )
533
+ global_irq_en = bwmon -> global_regs [F_GLOBAL_IRQ_ENABLE ];
534
+ else
535
+ global_irq_en = bwmon -> regs [F_GLOBAL_IRQ_ENABLE ];
536
+
392
537
/* Enable interrupts */
393
538
if (bwmon -> data -> quirks & BWMON_HAS_GLOBAL_IRQ )
394
- regmap_field_write (bwmon -> regs [ F_GLOBAL_IRQ_ENABLE ] ,
539
+ regmap_field_write (global_irq_en ,
395
540
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE );
541
+
396
542
regmap_field_write (bwmon -> regs [F_IRQ_ENABLE ], irq_enable );
397
543
398
544
/* Enable bwmon */
@@ -555,7 +701,9 @@ static int bwmon_init_regmap(struct platform_device *pdev,
555
701
struct device * dev = & pdev -> dev ;
556
702
void __iomem * base ;
557
703
struct regmap * map ;
704
+ int ret ;
558
705
706
+ /* Map the monitor base */
559
707
base = devm_platform_ioremap_resource (pdev , 0 );
560
708
if (IS_ERR (base ))
561
709
return dev_err_probe (dev , PTR_ERR (base ),
@@ -566,12 +714,35 @@ static int bwmon_init_regmap(struct platform_device *pdev,
566
714
return dev_err_probe (dev , PTR_ERR (map ),
567
715
"failed to initialize regmap\n" );
568
716
717
+ BUILD_BUG_ON (ARRAY_SIZE (msm8998_bwmon_global_reg_fields ) != F_NUM_GLOBAL_FIELDS );
569
718
BUILD_BUG_ON (ARRAY_SIZE (msm8998_bwmon_reg_fields ) != F_NUM_FIELDS );
719
+ BUILD_BUG_ON (ARRAY_SIZE (sdm845_cpu_bwmon_reg_fields ) != F_NUM_FIELDS );
570
720
BUILD_BUG_ON (ARRAY_SIZE (sdm845_llcc_bwmon_reg_fields ) != F_NUM_FIELDS );
571
721
572
- return devm_regmap_field_bulk_alloc (dev , map , bwmon -> regs ,
722
+ ret = devm_regmap_field_bulk_alloc (dev , map , bwmon -> regs ,
573
723
bwmon -> data -> regmap_fields ,
574
724
F_NUM_FIELDS );
725
+ if (ret )
726
+ return ret ;
727
+
728
+ if (bwmon -> data -> global_regmap_cfg ) {
729
+ /* Map the global base, if separate */
730
+ base = devm_platform_ioremap_resource (pdev , 1 );
731
+ if (IS_ERR (base ))
732
+ return dev_err_probe (dev , PTR_ERR (base ),
733
+ "failed to map bwmon global registers\n" );
734
+
735
+ map = devm_regmap_init_mmio (dev , base , bwmon -> data -> global_regmap_cfg );
736
+ if (IS_ERR (map ))
737
+ return dev_err_probe (dev , PTR_ERR (map ),
738
+ "failed to initialize global regmap\n" );
739
+
740
+ ret = devm_regmap_field_bulk_alloc (dev , map , bwmon -> global_regs ,
741
+ bwmon -> data -> global_regmap_fields ,
742
+ F_NUM_GLOBAL_FIELDS );
743
+ }
744
+
745
+ return ret ;
575
746
}
576
747
577
748
static int bwmon_probe (struct platform_device * pdev )
@@ -644,6 +815,21 @@ static const struct icc_bwmon_data msm8998_bwmon_data = {
644
815
.quirks = BWMON_HAS_GLOBAL_IRQ ,
645
816
.regmap_fields = msm8998_bwmon_reg_fields ,
646
817
.regmap_cfg = & msm8998_bwmon_regmap_cfg ,
818
+ .global_regmap_fields = msm8998_bwmon_global_reg_fields ,
819
+ .global_regmap_cfg = & msm8998_bwmon_global_regmap_cfg ,
820
+ };
821
+
822
+ static const struct icc_bwmon_data sdm845_cpu_bwmon_data = {
823
+ .sample_ms = 4 ,
824
+ .count_unit_kb = 64 ,
825
+ .default_highbw_kbps = 4800 * 1024 , /* 4.8 GBps */
826
+ .default_medbw_kbps = 512 * 1024 , /* 512 MBps */
827
+ .default_lowbw_kbps = 0 ,
828
+ .zone1_thres_count = 16 ,
829
+ .zone3_thres_count = 1 ,
830
+ .quirks = BWMON_HAS_GLOBAL_IRQ ,
831
+ .regmap_fields = sdm845_cpu_bwmon_reg_fields ,
832
+ .regmap_cfg = & sdm845_cpu_bwmon_regmap_cfg ,
647
833
};
648
834
649
835
static const struct icc_bwmon_data sdm845_llcc_bwmon_data = {
@@ -672,16 +858,18 @@ static const struct icc_bwmon_data sc7280_llcc_bwmon_data = {
672
858
};
673
859
674
860
static const struct of_device_id bwmon_of_match [] = {
675
- {
676
- .compatible = "qcom,msm8998-bwmon" ,
677
- .data = & msm8998_bwmon_data
678
- }, {
679
- .compatible = "qcom,sdm845-llcc-bwmon" ,
680
- .data = & sdm845_llcc_bwmon_data
681
- }, {
682
- .compatible = "qcom,sc7280-llcc-bwmon" ,
683
- .data = & sc7280_llcc_bwmon_data
684
- },
861
+ /* BWMONv4, separate monitor and global register spaces */
862
+ { .compatible = "qcom,msm8998-bwmon" , .data = & msm8998_bwmon_data },
863
+ /* BWMONv4, unified register space */
864
+ { .compatible = "qcom,sdm845-bwmon" , .data = & sdm845_cpu_bwmon_data },
865
+ /* BWMONv5 */
866
+ { .compatible = "qcom,sdm845-llcc-bwmon" , .data = & sdm845_llcc_bwmon_data },
867
+ { .compatible = "qcom,sc7280-llcc-bwmon" , .data = & sc7280_llcc_bwmon_data },
868
+
869
+ /* Compatibles kept for legacy reasons */
870
+ { .compatible = "qcom,sc7280-cpu-bwmon" , .data = & sdm845_cpu_bwmon_data },
871
+ { .compatible = "qcom,sc8280xp-cpu-bwmon" , .data = & sdm845_cpu_bwmon_data },
872
+ { .compatible = "qcom,sm8550-cpu-bwmon" , .data = & sdm845_cpu_bwmon_data },
685
873
{}
686
874
};
687
875
MODULE_DEVICE_TABLE (of , bwmon_of_match );
0 commit comments