3434/* Internal sampling clock frequency */
3535#define HW_TIMER_HZ 19200000
3636
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
3939/*
4040 * All values here and further are matching regmap fields, so without absolute
4141 * register offsets.
4242 */
4343#define BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE BIT(0)
4444
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+
4558#define BWMON_V4_IRQ_STATUS 0x100
4659#define BWMON_V4_IRQ_CLEAR 0x108
4760
118131#define BWMON_NEEDS_FORCE_CLEAR BIT(1)
119132
120133enum bwmon_fields {
134+ /* Global region fields, keep them at the top */
121135 F_GLOBAL_IRQ_CLEAR ,
122136 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 ,
124141 F_IRQ_CLEAR ,
125142 F_IRQ_ENABLE ,
126143 F_ENABLE ,
@@ -157,6 +174,9 @@ struct icc_bwmon_data {
157174
158175 const struct regmap_config * regmap_cfg ;
159176 const struct reg_field * regmap_fields ;
177+
178+ const struct regmap_config * global_regmap_cfg ;
179+ const struct reg_field * global_regmap_fields ;
160180};
161181
162182struct icc_bwmon {
@@ -165,6 +185,7 @@ struct icc_bwmon {
165185 int irq ;
166186
167187 struct regmap_field * regs [F_NUM_FIELDS ];
188+ struct regmap_field * global_regs [F_NUM_GLOBAL_FIELDS ];
168189
169190 unsigned int max_bw_kbps ;
170191 unsigned int min_bw_kbps ;
@@ -174,8 +195,8 @@ struct icc_bwmon {
174195
175196/* BWMON v4 */
176197static 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 ] = {} ,
179200 [F_IRQ_STATUS ] = REG_FIELD (BWMON_V4_IRQ_STATUS , 4 , 7 ),
180201 [F_IRQ_CLEAR ] = REG_FIELD (BWMON_V4_IRQ_CLEAR , 4 , 7 ),
181202 [F_IRQ_ENABLE ] = REG_FIELD (BWMON_V4_IRQ_ENABLE , 4 , 7 ),
@@ -201,7 +222,6 @@ static const struct reg_field msm8998_bwmon_reg_fields[] = {
201222};
202223
203224static const struct regmap_range msm8998_bwmon_reg_noread_ranges [] = {
204- regmap_reg_range (BWMON_V4_GLOBAL_IRQ_CLEAR , BWMON_V4_GLOBAL_IRQ_CLEAR ),
205225 regmap_reg_range (BWMON_V4_IRQ_CLEAR , BWMON_V4_IRQ_CLEAR ),
206226 regmap_reg_range (BWMON_V4_CLEAR , BWMON_V4_CLEAR ),
207227};
@@ -221,16 +241,33 @@ static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = {
221241 .n_yes_ranges = ARRAY_SIZE (msm8998_bwmon_reg_volatile_ranges ),
222242};
223243
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+
224258/*
225259 * Fill the cache for non-readable registers only as rest does not really
226260 * matter and can be read from the device.
227261 */
228262static const struct reg_default msm8998_bwmon_reg_defaults [] = {
229- { BWMON_V4_GLOBAL_IRQ_CLEAR , 0x0 },
230263 { BWMON_V4_IRQ_CLEAR , 0x0 },
231264 { BWMON_V4_CLEAR , 0x0 },
232265};
233266
267+ static const struct reg_default msm8998_bwmon_global_reg_defaults [] = {
268+ { BWMON_V4_GLOBAL_IRQ_CLEAR , 0x0 },
269+ };
270+
234271static const struct regmap_config msm8998_bwmon_regmap_cfg = {
235272 .reg_bits = 32 ,
236273 .reg_stride = 4 ,
@@ -251,6 +288,93 @@ static const struct regmap_config msm8998_bwmon_regmap_cfg = {
251288 .cache_type = REGCACHE_RBTREE ,
252289};
253290
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+
254378/* BWMON v5 */
255379static const struct reg_field sdm845_llcc_bwmon_reg_fields [] = {
256380 [F_GLOBAL_IRQ_CLEAR ] = {},
@@ -349,6 +473,13 @@ static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all)
349473
350474static void bwmon_clear_irq (struct icc_bwmon * bwmon )
351475{
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+
352483 /*
353484 * Clear zone and global interrupts. The order and barriers are
354485 * important. Quoting downstream Qualcomm msm-4.9 tree:
@@ -369,15 +500,22 @@ static void bwmon_clear_irq(struct icc_bwmon *bwmon)
369500 if (bwmon -> data -> quirks & BWMON_NEEDS_FORCE_CLEAR )
370501 regmap_field_force_write (bwmon -> regs [F_IRQ_CLEAR ], 0 );
371502 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 ,
373504 BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE );
374505}
375506
376507static void bwmon_disable (struct icc_bwmon * bwmon )
377508{
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+
378516 /* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
379517 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 );
381519 regmap_field_write (bwmon -> regs [F_IRQ_ENABLE ], 0x0 );
382520
383521 /*
@@ -389,10 +527,18 @@ static void bwmon_disable(struct icc_bwmon *bwmon)
389527
390528static void bwmon_enable (struct icc_bwmon * bwmon , unsigned int irq_enable )
391529{
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+
392537 /* Enable interrupts */
393538 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 ,
395540 BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE );
541+
396542 regmap_field_write (bwmon -> regs [F_IRQ_ENABLE ], irq_enable );
397543
398544 /* Enable bwmon */
@@ -555,7 +701,9 @@ static int bwmon_init_regmap(struct platform_device *pdev,
555701 struct device * dev = & pdev -> dev ;
556702 void __iomem * base ;
557703 struct regmap * map ;
704+ int ret ;
558705
706+ /* Map the monitor base */
559707 base = devm_platform_ioremap_resource (pdev , 0 );
560708 if (IS_ERR (base ))
561709 return dev_err_probe (dev , PTR_ERR (base ),
@@ -566,12 +714,35 @@ static int bwmon_init_regmap(struct platform_device *pdev,
566714 return dev_err_probe (dev , PTR_ERR (map ),
567715 "failed to initialize regmap\n" );
568716
717+ BUILD_BUG_ON (ARRAY_SIZE (msm8998_bwmon_global_reg_fields ) != F_NUM_GLOBAL_FIELDS );
569718 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 );
570720 BUILD_BUG_ON (ARRAY_SIZE (sdm845_llcc_bwmon_reg_fields ) != F_NUM_FIELDS );
571721
572- return devm_regmap_field_bulk_alloc (dev , map , bwmon -> regs ,
722+ ret = devm_regmap_field_bulk_alloc (dev , map , bwmon -> regs ,
573723 bwmon -> data -> regmap_fields ,
574724 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 ;
575746}
576747
577748static int bwmon_probe (struct platform_device * pdev )
@@ -644,6 +815,21 @@ static const struct icc_bwmon_data msm8998_bwmon_data = {
644815 .quirks = BWMON_HAS_GLOBAL_IRQ ,
645816 .regmap_fields = msm8998_bwmon_reg_fields ,
646817 .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 ,
647833};
648834
649835static const struct icc_bwmon_data sdm845_llcc_bwmon_data = {
@@ -672,16 +858,18 @@ static const struct icc_bwmon_data sc7280_llcc_bwmon_data = {
672858};
673859
674860static 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 },
685873 {}
686874};
687875MODULE_DEVICE_TABLE (of , bwmon_of_match );
0 commit comments