2022-07-04 15:17:28 +03:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright ( c ) 2014 - 2018 , The Linux Foundation . All rights reserved .
* Copyright ( C ) 2021 - 2022 Linaro Ltd
* Author : Krzysztof Kozlowski < krzysztof . kozlowski @ linaro . org > , based on
* previous work of Thara Gopinath and msm - 4.9 downstream sources .
*/
2022-07-28 14:37:44 +03:00
# include <linux/err.h>
2022-07-04 15:17:28 +03:00
# include <linux/interconnect.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of_device.h>
# include <linux/platform_device.h>
# include <linux/pm_opp.h>
2022-07-28 14:37:44 +03:00
# include <linux/regmap.h>
2022-07-04 15:17:28 +03:00
# include <linux/sizes.h>
/*
* The BWMON samples data throughput within ' sample_ms ' time . With three
* configurable thresholds ( Low , Medium and High ) gives four windows ( called
* zones ) of current bandwidth :
*
* Zone 0 : byte count < THRES_LO
* Zone 1 : THRES_LO < byte count < THRES_MED
* Zone 2 : THRES_MED < byte count < THRES_HIGH
* Zone 3 : THRES_HIGH < byte count
*
* Zones 0 and 2 are not used by this driver .
*/
/* Internal sampling clock frequency */
# define HW_TIMER_HZ 19200000
2023-03-15 17:11:21 +03:00
# define BWMON_V4_GLOBAL_IRQ_CLEAR 0x108
# define BWMON_V4_GLOBAL_IRQ_ENABLE 0x10c
2022-07-28 14:37:44 +03:00
/*
* All values here and further are matching regmap fields , so without absolute
* register offsets .
*/
# define BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE BIT(0)
2023-03-15 17:11:21 +03:00
/*
* Starting with SDM845 , the BWMON4 register space has changed a bit :
* the global registers were jammed into the beginning of the monitor region .
* To keep the proper offsets , one would have to map < GLOBAL_BASE 0x200 > and
* < GLOBAL_BASE + 0x100 0x300 > , which is straight up wrong .
* To facilitate for that , while allowing the older , arguably more proper
* implementations to work , offset the global registers by - 0x100 to avoid
* having to map half of the global registers twice .
*/
# define BWMON_V4_845_OFFSET 0x100
# define BWMON_V4_GLOBAL_IRQ_CLEAR_845 (BWMON_V4_GLOBAL_IRQ_CLEAR - BWMON_V4_845_OFFSET)
# define BWMON_V4_GLOBAL_IRQ_ENABLE_845 (BWMON_V4_GLOBAL_IRQ_ENABLE - BWMON_V4_845_OFFSET)
2022-07-28 14:37:44 +03:00
# define BWMON_V4_IRQ_STATUS 0x100
# define BWMON_V4_IRQ_CLEAR 0x108
# define BWMON_V4_IRQ_ENABLE 0x10c
# define BWMON_IRQ_ENABLE_MASK (BIT(1) | BIT(3))
2022-07-28 14:37:46 +03:00
# define BWMON_V5_IRQ_STATUS 0x000
# define BWMON_V5_IRQ_CLEAR 0x008
# define BWMON_V5_IRQ_ENABLE 0x00c
2022-07-28 14:37:44 +03:00
# define BWMON_V4_ENABLE 0x2a0
2022-07-28 14:37:46 +03:00
# define BWMON_V5_ENABLE 0x010
2022-07-04 15:17:28 +03:00
# define BWMON_ENABLE_ENABLE BIT(0)
2022-07-28 14:37:44 +03:00
# define BWMON_V4_CLEAR 0x2a4
2022-07-28 14:37:46 +03:00
# define BWMON_V5_CLEAR 0x014
2022-07-04 15:17:28 +03:00
# define BWMON_CLEAR_CLEAR BIT(0)
2022-07-28 14:37:42 +03:00
# define BWMON_CLEAR_CLEAR_ALL BIT(1)
2022-07-04 15:17:28 +03:00
2022-07-28 14:37:44 +03:00
# define BWMON_V4_SAMPLE_WINDOW 0x2a8
2022-07-28 14:37:46 +03:00
# define BWMON_V5_SAMPLE_WINDOW 0x020
2022-07-28 14:37:44 +03:00
# define BWMON_V4_THRESHOLD_HIGH 0x2ac
# define BWMON_V4_THRESHOLD_MED 0x2b0
# define BWMON_V4_THRESHOLD_LOW 0x2b4
2022-07-28 14:37:46 +03:00
# define BWMON_V5_THRESHOLD_HIGH 0x024
# define BWMON_V5_THRESHOLD_MED 0x028
# define BWMON_V5_THRESHOLD_LOW 0x02c
2022-07-04 15:17:28 +03:00
2022-07-28 14:37:44 +03:00
# define BWMON_V4_ZONE_ACTIONS 0x2b8
2022-07-28 14:37:46 +03:00
# define BWMON_V5_ZONE_ACTIONS 0x030
2022-07-04 15:17:28 +03:00
/*
* Actions to perform on some zone ' z ' when current zone hits the threshold :
* Increment counter of zone ' z '
*/
# define BWMON_ZONE_ACTIONS_INCREMENT(z) (0x2 << ((z) * 2))
/* Clear counter of zone 'z' */
# define BWMON_ZONE_ACTIONS_CLEAR(z) (0x1 << ((z) * 2))
/* Zone 0 threshold hit: Clear zone count */
# define BWMON_ZONE_ACTIONS_ZONE0 (BWMON_ZONE_ACTIONS_CLEAR(0))
/* Zone 1 threshold hit: Increment zone count & clear lower zones */
# define BWMON_ZONE_ACTIONS_ZONE1 (BWMON_ZONE_ACTIONS_INCREMENT(1) | \
BWMON_ZONE_ACTIONS_CLEAR ( 0 ) )
/* Zone 2 threshold hit: Increment zone count & clear lower zones */
# define BWMON_ZONE_ACTIONS_ZONE2 (BWMON_ZONE_ACTIONS_INCREMENT(2) | \
BWMON_ZONE_ACTIONS_CLEAR ( 1 ) | \
BWMON_ZONE_ACTIONS_CLEAR ( 0 ) )
/* Zone 3 threshold hit: Increment zone count & clear lower zones */
# define BWMON_ZONE_ACTIONS_ZONE3 (BWMON_ZONE_ACTIONS_INCREMENT(3) | \
BWMON_ZONE_ACTIONS_CLEAR ( 2 ) | \
BWMON_ZONE_ACTIONS_CLEAR ( 1 ) | \
BWMON_ZONE_ACTIONS_CLEAR ( 0 ) )
/*
2022-07-28 14:37:44 +03:00
* There is no clear documentation / explanation of BWMON_V4_THRESHOLD_COUNT
2022-07-04 15:17:28 +03:00
* register . Based on observations , this is number of times one threshold has to
* be reached , to trigger interrupt in given zone .
*
* 0xff are maximum values meant to ignore the zones 0 and 2.
*/
2022-07-28 14:37:44 +03:00
# define BWMON_V4_THRESHOLD_COUNT 0x2bc
2022-07-28 14:37:46 +03:00
# define BWMON_V5_THRESHOLD_COUNT 0x034
2022-07-04 15:17:28 +03:00
# define BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT 0xff
# define BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT 0xff
2022-07-28 14:37:44 +03:00
# define BWMON_V4_ZONE_MAX(zone) (0x2e0 + 4 * (zone))
2022-07-28 14:37:46 +03:00
# define BWMON_V5_ZONE_MAX(zone) (0x044 + 4 * (zone))
2022-07-28 14:37:44 +03:00
2022-07-28 14:37:45 +03:00
/* Quirks for specific BWMON types */
# define BWMON_HAS_GLOBAL_IRQ BIT(0)
2022-09-02 07:35:10 +03:00
# define BWMON_NEEDS_FORCE_CLEAR BIT(1)
2022-07-28 14:37:45 +03:00
2022-07-28 14:37:44 +03:00
enum bwmon_fields {
2023-03-15 17:11:21 +03:00
/* Global region fields, keep them at the top */
2022-07-28 14:37:44 +03:00
F_GLOBAL_IRQ_CLEAR ,
F_GLOBAL_IRQ_ENABLE ,
2023-03-15 17:11:21 +03:00
F_NUM_GLOBAL_FIELDS ,
/* Monitor region fields */
F_IRQ_STATUS = F_NUM_GLOBAL_FIELDS ,
2022-07-28 14:37:44 +03:00
F_IRQ_CLEAR ,
F_IRQ_ENABLE ,
F_ENABLE ,
F_CLEAR ,
F_SAMPLE_WINDOW ,
F_THRESHOLD_HIGH ,
F_THRESHOLD_MED ,
F_THRESHOLD_LOW ,
F_ZONE_ACTIONS_ZONE0 ,
F_ZONE_ACTIONS_ZONE1 ,
F_ZONE_ACTIONS_ZONE2 ,
F_ZONE_ACTIONS_ZONE3 ,
F_THRESHOLD_COUNT_ZONE0 ,
F_THRESHOLD_COUNT_ZONE1 ,
F_THRESHOLD_COUNT_ZONE2 ,
F_THRESHOLD_COUNT_ZONE3 ,
F_ZONE0_MAX ,
F_ZONE1_MAX ,
F_ZONE2_MAX ,
F_ZONE3_MAX ,
F_NUM_FIELDS
} ;
2022-07-04 15:17:28 +03:00
struct icc_bwmon_data {
unsigned int sample_ms ;
2022-07-28 14:37:43 +03:00
unsigned int count_unit_kb ; /* kbytes */
2022-07-04 15:17:28 +03:00
unsigned int default_highbw_kbps ;
unsigned int default_medbw_kbps ;
unsigned int default_lowbw_kbps ;
u8 zone1_thres_count ;
u8 zone3_thres_count ;
2022-07-28 14:37:45 +03:00
unsigned int quirks ;
2022-07-28 14:37:44 +03:00
const struct regmap_config * regmap_cfg ;
const struct reg_field * regmap_fields ;
2023-03-15 17:11:21 +03:00
const struct regmap_config * global_regmap_cfg ;
const struct reg_field * global_regmap_fields ;
2022-07-04 15:17:28 +03:00
} ;
struct icc_bwmon {
struct device * dev ;
2022-07-28 14:37:41 +03:00
const struct icc_bwmon_data * data ;
2022-07-04 15:17:28 +03:00
int irq ;
2022-07-28 14:37:44 +03:00
struct regmap_field * regs [ F_NUM_FIELDS ] ;
2023-03-15 17:11:21 +03:00
struct regmap_field * global_regs [ F_NUM_GLOBAL_FIELDS ] ;
2022-07-28 14:37:44 +03:00
2022-07-04 15:17:28 +03:00
unsigned int max_bw_kbps ;
unsigned int min_bw_kbps ;
unsigned int target_kbps ;
unsigned int current_kbps ;
} ;
2022-07-28 14:37:44 +03:00
/* BWMON v4 */
static const struct reg_field msm8998_bwmon_reg_fields [ ] = {
2023-03-15 17:11:21 +03:00
[ F_GLOBAL_IRQ_CLEAR ] = { } ,
[ F_GLOBAL_IRQ_ENABLE ] = { } ,
2022-07-28 14:37:44 +03:00
[ F_IRQ_STATUS ] = REG_FIELD ( BWMON_V4_IRQ_STATUS , 4 , 7 ) ,
[ F_IRQ_CLEAR ] = REG_FIELD ( BWMON_V4_IRQ_CLEAR , 4 , 7 ) ,
[ F_IRQ_ENABLE ] = REG_FIELD ( BWMON_V4_IRQ_ENABLE , 4 , 7 ) ,
/* F_ENABLE covers entire register to disable other features */
[ F_ENABLE ] = REG_FIELD ( BWMON_V4_ENABLE , 0 , 31 ) ,
[ F_CLEAR ] = REG_FIELD ( BWMON_V4_CLEAR , 0 , 1 ) ,
[ F_SAMPLE_WINDOW ] = REG_FIELD ( BWMON_V4_SAMPLE_WINDOW , 0 , 23 ) ,
[ F_THRESHOLD_HIGH ] = REG_FIELD ( BWMON_V4_THRESHOLD_HIGH , 0 , 11 ) ,
[ F_THRESHOLD_MED ] = REG_FIELD ( BWMON_V4_THRESHOLD_MED , 0 , 11 ) ,
[ F_THRESHOLD_LOW ] = REG_FIELD ( BWMON_V4_THRESHOLD_LOW , 0 , 11 ) ,
[ F_ZONE_ACTIONS_ZONE0 ] = REG_FIELD ( BWMON_V4_ZONE_ACTIONS , 0 , 7 ) ,
[ F_ZONE_ACTIONS_ZONE1 ] = REG_FIELD ( BWMON_V4_ZONE_ACTIONS , 8 , 15 ) ,
[ F_ZONE_ACTIONS_ZONE2 ] = REG_FIELD ( BWMON_V4_ZONE_ACTIONS , 16 , 23 ) ,
[ F_ZONE_ACTIONS_ZONE3 ] = REG_FIELD ( BWMON_V4_ZONE_ACTIONS , 24 , 31 ) ,
[ F_THRESHOLD_COUNT_ZONE0 ] = REG_FIELD ( BWMON_V4_THRESHOLD_COUNT , 0 , 7 ) ,
[ F_THRESHOLD_COUNT_ZONE1 ] = REG_FIELD ( BWMON_V4_THRESHOLD_COUNT , 8 , 15 ) ,
[ F_THRESHOLD_COUNT_ZONE2 ] = REG_FIELD ( BWMON_V4_THRESHOLD_COUNT , 16 , 23 ) ,
[ F_THRESHOLD_COUNT_ZONE3 ] = REG_FIELD ( BWMON_V4_THRESHOLD_COUNT , 24 , 31 ) ,
[ F_ZONE0_MAX ] = REG_FIELD ( BWMON_V4_ZONE_MAX ( 0 ) , 0 , 11 ) ,
[ F_ZONE1_MAX ] = REG_FIELD ( BWMON_V4_ZONE_MAX ( 1 ) , 0 , 11 ) ,
[ F_ZONE2_MAX ] = REG_FIELD ( BWMON_V4_ZONE_MAX ( 2 ) , 0 , 11 ) ,
[ F_ZONE3_MAX ] = REG_FIELD ( BWMON_V4_ZONE_MAX ( 3 ) , 0 , 11 ) ,
} ;
static const struct regmap_range msm8998_bwmon_reg_noread_ranges [ ] = {
regmap_reg_range ( BWMON_V4_IRQ_CLEAR , BWMON_V4_IRQ_CLEAR ) ,
regmap_reg_range ( BWMON_V4_CLEAR , BWMON_V4_CLEAR ) ,
} ;
static const struct regmap_access_table msm8998_bwmon_reg_read_table = {
. no_ranges = msm8998_bwmon_reg_noread_ranges ,
. n_no_ranges = ARRAY_SIZE ( msm8998_bwmon_reg_noread_ranges ) ,
} ;
static const struct regmap_range msm8998_bwmon_reg_volatile_ranges [ ] = {
regmap_reg_range ( BWMON_V4_IRQ_STATUS , BWMON_V4_IRQ_STATUS ) ,
regmap_reg_range ( BWMON_V4_ZONE_MAX ( 0 ) , BWMON_V4_ZONE_MAX ( 3 ) ) ,
} ;
static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = {
. yes_ranges = msm8998_bwmon_reg_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( msm8998_bwmon_reg_volatile_ranges ) ,
} ;
2023-03-15 17:11:21 +03:00
static const struct reg_field msm8998_bwmon_global_reg_fields [ ] = {
[ F_GLOBAL_IRQ_CLEAR ] = REG_FIELD ( BWMON_V4_GLOBAL_IRQ_CLEAR , 0 , 0 ) ,
[ F_GLOBAL_IRQ_ENABLE ] = REG_FIELD ( BWMON_V4_GLOBAL_IRQ_ENABLE , 0 , 0 ) ,
} ;
static const struct regmap_range msm8998_bwmon_global_reg_noread_ranges [ ] = {
regmap_reg_range ( BWMON_V4_GLOBAL_IRQ_CLEAR , BWMON_V4_GLOBAL_IRQ_CLEAR ) ,
} ;
static const struct regmap_access_table msm8998_bwmon_global_reg_read_table = {
. no_ranges = msm8998_bwmon_global_reg_noread_ranges ,
. n_no_ranges = ARRAY_SIZE ( msm8998_bwmon_global_reg_noread_ranges ) ,
} ;
2022-07-28 14:37:44 +03:00
/*
* Fill the cache for non - readable registers only as rest does not really
* matter and can be read from the device .
*/
static const struct reg_default msm8998_bwmon_reg_defaults [ ] = {
{ BWMON_V4_IRQ_CLEAR , 0x0 } ,
{ BWMON_V4_CLEAR , 0x0 } ,
} ;
2023-03-15 17:11:21 +03:00
static const struct reg_default msm8998_bwmon_global_reg_defaults [ ] = {
{ BWMON_V4_GLOBAL_IRQ_CLEAR , 0x0 } ,
} ;
2022-07-28 14:37:44 +03:00
static const struct regmap_config msm8998_bwmon_regmap_cfg = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
/*
* No concurrent access expected - driver has one interrupt handler ,
* regmap is not shared , no driver or user - space API .
*/
. disable_locking = true ,
. rd_table = & msm8998_bwmon_reg_read_table ,
. volatile_table = & msm8998_bwmon_reg_volatile_table ,
. reg_defaults = msm8998_bwmon_reg_defaults ,
. num_reg_defaults = ARRAY_SIZE ( msm8998_bwmon_reg_defaults ) ,
/*
* Cache is necessary for using regmap fields with non - readable
* registers .
*/
. cache_type = REGCACHE_RBTREE ,
} ;
2023-03-15 17:11:21 +03:00
static const struct regmap_config msm8998_bwmon_global_regmap_cfg = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
/*
* No concurrent access expected - driver has one interrupt handler ,
* regmap is not shared , no driver or user - space API .
*/
. disable_locking = true ,
. rd_table = & msm8998_bwmon_global_reg_read_table ,
. reg_defaults = msm8998_bwmon_global_reg_defaults ,
. num_reg_defaults = ARRAY_SIZE ( msm8998_bwmon_global_reg_defaults ) ,
/*
* Cache is necessary for using regmap fields with non - readable
* registers .
*/
. cache_type = REGCACHE_RBTREE ,
} ;
static const struct reg_field sdm845_cpu_bwmon_reg_fields [ ] = {
[ F_GLOBAL_IRQ_CLEAR ] = REG_FIELD ( BWMON_V4_GLOBAL_IRQ_CLEAR_845 , 0 , 0 ) ,
[ F_GLOBAL_IRQ_ENABLE ] = REG_FIELD ( BWMON_V4_GLOBAL_IRQ_ENABLE_845 , 0 , 0 ) ,
[ F_IRQ_STATUS ] = REG_FIELD ( BWMON_V4_IRQ_STATUS , 4 , 7 ) ,
[ F_IRQ_CLEAR ] = REG_FIELD ( BWMON_V4_IRQ_CLEAR , 4 , 7 ) ,
[ F_IRQ_ENABLE ] = REG_FIELD ( BWMON_V4_IRQ_ENABLE , 4 , 7 ) ,
/* F_ENABLE covers entire register to disable other features */
[ F_ENABLE ] = REG_FIELD ( BWMON_V4_ENABLE , 0 , 31 ) ,
[ F_CLEAR ] = REG_FIELD ( BWMON_V4_CLEAR , 0 , 1 ) ,
[ F_SAMPLE_WINDOW ] = REG_FIELD ( BWMON_V4_SAMPLE_WINDOW , 0 , 23 ) ,
[ F_THRESHOLD_HIGH ] = REG_FIELD ( BWMON_V4_THRESHOLD_HIGH , 0 , 11 ) ,
[ F_THRESHOLD_MED ] = REG_FIELD ( BWMON_V4_THRESHOLD_MED , 0 , 11 ) ,
[ F_THRESHOLD_LOW ] = REG_FIELD ( BWMON_V4_THRESHOLD_LOW , 0 , 11 ) ,
[ F_ZONE_ACTIONS_ZONE0 ] = REG_FIELD ( BWMON_V4_ZONE_ACTIONS , 0 , 7 ) ,
[ F_ZONE_ACTIONS_ZONE1 ] = REG_FIELD ( BWMON_V4_ZONE_ACTIONS , 8 , 15 ) ,
[ F_ZONE_ACTIONS_ZONE2 ] = REG_FIELD ( BWMON_V4_ZONE_ACTIONS , 16 , 23 ) ,
[ F_ZONE_ACTIONS_ZONE3 ] = REG_FIELD ( BWMON_V4_ZONE_ACTIONS , 24 , 31 ) ,
[ F_THRESHOLD_COUNT_ZONE0 ] = REG_FIELD ( BWMON_V4_THRESHOLD_COUNT , 0 , 7 ) ,
[ F_THRESHOLD_COUNT_ZONE1 ] = REG_FIELD ( BWMON_V4_THRESHOLD_COUNT , 8 , 15 ) ,
[ F_THRESHOLD_COUNT_ZONE2 ] = REG_FIELD ( BWMON_V4_THRESHOLD_COUNT , 16 , 23 ) ,
[ F_THRESHOLD_COUNT_ZONE3 ] = REG_FIELD ( BWMON_V4_THRESHOLD_COUNT , 24 , 31 ) ,
[ F_ZONE0_MAX ] = REG_FIELD ( BWMON_V4_ZONE_MAX ( 0 ) , 0 , 11 ) ,
[ F_ZONE1_MAX ] = REG_FIELD ( BWMON_V4_ZONE_MAX ( 1 ) , 0 , 11 ) ,
[ F_ZONE2_MAX ] = REG_FIELD ( BWMON_V4_ZONE_MAX ( 2 ) , 0 , 11 ) ,
[ F_ZONE3_MAX ] = REG_FIELD ( BWMON_V4_ZONE_MAX ( 3 ) , 0 , 11 ) ,
} ;
static const struct regmap_range sdm845_cpu_bwmon_reg_noread_ranges [ ] = {
regmap_reg_range ( BWMON_V4_GLOBAL_IRQ_CLEAR_845 , BWMON_V4_GLOBAL_IRQ_CLEAR_845 ) ,
regmap_reg_range ( BWMON_V4_IRQ_CLEAR , BWMON_V4_IRQ_CLEAR ) ,
regmap_reg_range ( BWMON_V4_CLEAR , BWMON_V4_CLEAR ) ,
} ;
static const struct regmap_access_table sdm845_cpu_bwmon_reg_read_table = {
. no_ranges = sdm845_cpu_bwmon_reg_noread_ranges ,
. n_no_ranges = ARRAY_SIZE ( sdm845_cpu_bwmon_reg_noread_ranges ) ,
} ;
/*
* Fill the cache for non - readable registers only as rest does not really
* matter and can be read from the device .
*/
static const struct reg_default sdm845_cpu_bwmon_reg_defaults [ ] = {
{ BWMON_V4_GLOBAL_IRQ_CLEAR_845 , 0x0 } ,
{ BWMON_V4_IRQ_CLEAR , 0x0 } ,
{ BWMON_V4_CLEAR , 0x0 } ,
} ;
static const struct regmap_config sdm845_cpu_bwmon_regmap_cfg = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
/*
* No concurrent access expected - driver has one interrupt handler ,
* regmap is not shared , no driver or user - space API .
*/
. disable_locking = true ,
. rd_table = & sdm845_cpu_bwmon_reg_read_table ,
. volatile_table = & msm8998_bwmon_reg_volatile_table ,
. reg_defaults = sdm845_cpu_bwmon_reg_defaults ,
. num_reg_defaults = ARRAY_SIZE ( sdm845_cpu_bwmon_reg_defaults ) ,
/*
* Cache is necessary for using regmap fields with non - readable
* registers .
*/
. cache_type = REGCACHE_RBTREE ,
} ;
2022-07-28 14:37:46 +03:00
/* BWMON v5 */
static const struct reg_field sdm845_llcc_bwmon_reg_fields [ ] = {
[ F_GLOBAL_IRQ_CLEAR ] = { } ,
[ F_GLOBAL_IRQ_ENABLE ] = { } ,
[ F_IRQ_STATUS ] = REG_FIELD ( BWMON_V5_IRQ_STATUS , 0 , 3 ) ,
[ F_IRQ_CLEAR ] = REG_FIELD ( BWMON_V5_IRQ_CLEAR , 0 , 3 ) ,
[ F_IRQ_ENABLE ] = REG_FIELD ( BWMON_V5_IRQ_ENABLE , 0 , 3 ) ,
/* F_ENABLE covers entire register to disable other features */
[ F_ENABLE ] = REG_FIELD ( BWMON_V5_ENABLE , 0 , 31 ) ,
[ F_CLEAR ] = REG_FIELD ( BWMON_V5_CLEAR , 0 , 1 ) ,
[ F_SAMPLE_WINDOW ] = REG_FIELD ( BWMON_V5_SAMPLE_WINDOW , 0 , 19 ) ,
[ F_THRESHOLD_HIGH ] = REG_FIELD ( BWMON_V5_THRESHOLD_HIGH , 0 , 11 ) ,
[ F_THRESHOLD_MED ] = REG_FIELD ( BWMON_V5_THRESHOLD_MED , 0 , 11 ) ,
[ F_THRESHOLD_LOW ] = REG_FIELD ( BWMON_V5_THRESHOLD_LOW , 0 , 11 ) ,
[ F_ZONE_ACTIONS_ZONE0 ] = REG_FIELD ( BWMON_V5_ZONE_ACTIONS , 0 , 7 ) ,
[ F_ZONE_ACTIONS_ZONE1 ] = REG_FIELD ( BWMON_V5_ZONE_ACTIONS , 8 , 15 ) ,
[ F_ZONE_ACTIONS_ZONE2 ] = REG_FIELD ( BWMON_V5_ZONE_ACTIONS , 16 , 23 ) ,
[ F_ZONE_ACTIONS_ZONE3 ] = REG_FIELD ( BWMON_V5_ZONE_ACTIONS , 24 , 31 ) ,
[ F_THRESHOLD_COUNT_ZONE0 ] = REG_FIELD ( BWMON_V5_THRESHOLD_COUNT , 0 , 7 ) ,
[ F_THRESHOLD_COUNT_ZONE1 ] = REG_FIELD ( BWMON_V5_THRESHOLD_COUNT , 8 , 15 ) ,
[ F_THRESHOLD_COUNT_ZONE2 ] = REG_FIELD ( BWMON_V5_THRESHOLD_COUNT , 16 , 23 ) ,
[ F_THRESHOLD_COUNT_ZONE3 ] = REG_FIELD ( BWMON_V5_THRESHOLD_COUNT , 24 , 31 ) ,
[ F_ZONE0_MAX ] = REG_FIELD ( BWMON_V5_ZONE_MAX ( 0 ) , 0 , 11 ) ,
[ F_ZONE1_MAX ] = REG_FIELD ( BWMON_V5_ZONE_MAX ( 1 ) , 0 , 11 ) ,
[ F_ZONE2_MAX ] = REG_FIELD ( BWMON_V5_ZONE_MAX ( 2 ) , 0 , 11 ) ,
[ F_ZONE3_MAX ] = REG_FIELD ( BWMON_V5_ZONE_MAX ( 3 ) , 0 , 11 ) ,
} ;
static const struct regmap_range sdm845_llcc_bwmon_reg_noread_ranges [ ] = {
regmap_reg_range ( BWMON_V5_IRQ_CLEAR , BWMON_V5_IRQ_CLEAR ) ,
regmap_reg_range ( BWMON_V5_CLEAR , BWMON_V5_CLEAR ) ,
} ;
static const struct regmap_access_table sdm845_llcc_bwmon_reg_read_table = {
. no_ranges = sdm845_llcc_bwmon_reg_noread_ranges ,
. n_no_ranges = ARRAY_SIZE ( sdm845_llcc_bwmon_reg_noread_ranges ) ,
} ;
static const struct regmap_range sdm845_llcc_bwmon_reg_volatile_ranges [ ] = {
regmap_reg_range ( BWMON_V5_IRQ_STATUS , BWMON_V5_IRQ_STATUS ) ,
regmap_reg_range ( BWMON_V5_ZONE_MAX ( 0 ) , BWMON_V5_ZONE_MAX ( 3 ) ) ,
} ;
static const struct regmap_access_table sdm845_llcc_bwmon_reg_volatile_table = {
. yes_ranges = sdm845_llcc_bwmon_reg_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( sdm845_llcc_bwmon_reg_volatile_ranges ) ,
} ;
/*
* Fill the cache for non - readable registers only as rest does not really
* matter and can be read from the device .
*/
static const struct reg_default sdm845_llcc_bwmon_reg_defaults [ ] = {
{ BWMON_V5_IRQ_CLEAR , 0x0 } ,
{ BWMON_V5_CLEAR , 0x0 } ,
} ;
static const struct regmap_config sdm845_llcc_bwmon_regmap_cfg = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
/*
* No concurrent access expected - driver has one interrupt handler ,
* regmap is not shared , no driver or user - space API .
*/
. disable_locking = true ,
. rd_table = & sdm845_llcc_bwmon_reg_read_table ,
. volatile_table = & sdm845_llcc_bwmon_reg_volatile_table ,
. reg_defaults = sdm845_llcc_bwmon_reg_defaults ,
. num_reg_defaults = ARRAY_SIZE ( sdm845_llcc_bwmon_reg_defaults ) ,
/*
* Cache is necessary for using regmap fields with non - readable
* registers .
*/
. cache_type = REGCACHE_RBTREE ,
} ;
2022-07-28 14:37:42 +03:00
static void bwmon_clear_counters ( struct icc_bwmon * bwmon , bool clear_all )
2022-07-04 15:17:28 +03:00
{
2022-07-28 14:37:42 +03:00
unsigned int val = BWMON_CLEAR_CLEAR ;
if ( clear_all )
val | = BWMON_CLEAR_CLEAR_ALL ;
2022-07-04 15:17:28 +03:00
/*
* Clear counters . The order and barriers are
* important . Quoting downstream Qualcomm msm - 4.9 tree :
*
* The counter clear and IRQ clear bits are not in the same 4 KB
* region . So , we need to make sure the counter clear is completed
* before we try to clear the IRQ or do any other counter operations .
*/
2022-07-28 14:37:44 +03:00
regmap_field_force_write ( bwmon - > regs [ F_CLEAR ] , val ) ;
2022-09-02 07:35:10 +03:00
if ( bwmon - > data - > quirks & BWMON_NEEDS_FORCE_CLEAR )
regmap_field_force_write ( bwmon - > regs [ F_CLEAR ] , 0 ) ;
2022-07-04 15:17:28 +03:00
}
static void bwmon_clear_irq ( struct icc_bwmon * bwmon )
{
2023-03-15 17:11:21 +03:00
struct regmap_field * global_irq_clr ;
if ( bwmon - > data - > global_regmap_fields )
global_irq_clr = bwmon - > global_regs [ F_GLOBAL_IRQ_CLEAR ] ;
else
global_irq_clr = bwmon - > regs [ F_GLOBAL_IRQ_CLEAR ] ;
2022-07-04 15:17:28 +03:00
/*
* Clear zone and global interrupts . The order and barriers are
* important . Quoting downstream Qualcomm msm - 4.9 tree :
*
* Synchronize the local interrupt clear in mon_irq_clear ( )
* with the global interrupt clear here . Otherwise , the CPU
* may reorder the two writes and clear the global interrupt
* before the local interrupt , causing the global interrupt
* to be retriggered by the local interrupt still being high .
*
* Similarly , because the global registers are in a different
* region than the local registers , we need to ensure any register
* writes to enable the monitor after this call are ordered with the
* clearing here so that local writes don ' t happen before the
* interrupt is cleared .
*/
2022-07-28 14:37:44 +03:00
regmap_field_force_write ( bwmon - > regs [ F_IRQ_CLEAR ] , BWMON_IRQ_ENABLE_MASK ) ;
2022-09-02 07:35:10 +03:00
if ( bwmon - > data - > quirks & BWMON_NEEDS_FORCE_CLEAR )
regmap_field_force_write ( bwmon - > regs [ F_IRQ_CLEAR ] , 0 ) ;
2022-07-28 14:37:45 +03:00
if ( bwmon - > data - > quirks & BWMON_HAS_GLOBAL_IRQ )
2023-03-15 17:11:21 +03:00
regmap_field_force_write ( global_irq_clr ,
2022-07-28 14:37:45 +03:00
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE ) ;
2022-07-04 15:17:28 +03:00
}
static void bwmon_disable ( struct icc_bwmon * bwmon )
{
2023-03-15 17:11:21 +03:00
struct regmap_field * global_irq_en ;
if ( bwmon - > data - > global_regmap_fields )
global_irq_en = bwmon - > global_regs [ F_GLOBAL_IRQ_ENABLE ] ;
else
global_irq_en = bwmon - > regs [ F_GLOBAL_IRQ_ENABLE ] ;
2022-07-04 15:17:28 +03:00
/* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
2022-07-28 14:37:45 +03:00
if ( bwmon - > data - > quirks & BWMON_HAS_GLOBAL_IRQ )
2023-03-15 17:11:21 +03:00
regmap_field_write ( global_irq_en , 0x0 ) ;
2022-07-28 14:37:44 +03:00
regmap_field_write ( bwmon - > regs [ F_IRQ_ENABLE ] , 0x0 ) ;
2022-07-04 15:17:28 +03:00
/*
* Disable bwmon . Must happen before bwmon_clear_irq ( ) to avoid spurious
* IRQ .
*/
2022-07-28 14:37:44 +03:00
regmap_field_write ( bwmon - > regs [ F_ENABLE ] , 0x0 ) ;
2022-07-04 15:17:28 +03:00
}
static void bwmon_enable ( struct icc_bwmon * bwmon , unsigned int irq_enable )
{
2023-03-15 17:11:21 +03:00
struct regmap_field * global_irq_en ;
if ( bwmon - > data - > global_regmap_fields )
global_irq_en = bwmon - > global_regs [ F_GLOBAL_IRQ_ENABLE ] ;
else
global_irq_en = bwmon - > regs [ F_GLOBAL_IRQ_ENABLE ] ;
2022-07-04 15:17:28 +03:00
/* Enable interrupts */
2022-07-28 14:37:45 +03:00
if ( bwmon - > data - > quirks & BWMON_HAS_GLOBAL_IRQ )
2023-03-15 17:11:21 +03:00
regmap_field_write ( global_irq_en ,
2022-07-28 14:37:45 +03:00
BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE ) ;
2023-03-15 17:11:21 +03:00
2022-07-28 14:37:44 +03:00
regmap_field_write ( bwmon - > regs [ F_IRQ_ENABLE ] , irq_enable ) ;
2022-07-04 15:17:28 +03:00
/* Enable bwmon */
2022-07-28 14:37:44 +03:00
regmap_field_write ( bwmon - > regs [ F_ENABLE ] , BWMON_ENABLE_ENABLE ) ;
2022-07-04 15:17:28 +03:00
}
2022-07-28 14:37:43 +03:00
static unsigned int bwmon_kbps_to_count ( struct icc_bwmon * bwmon ,
unsigned int kbps )
2022-07-04 15:17:28 +03:00
{
2022-07-28 14:37:43 +03:00
return kbps / bwmon - > data - > count_unit_kb ;
2022-07-04 15:17:28 +03:00
}
2022-07-28 14:37:44 +03:00
static void bwmon_set_threshold ( struct icc_bwmon * bwmon ,
struct regmap_field * reg , unsigned int kbps )
2022-07-04 15:17:28 +03:00
{
unsigned int thres ;
2022-07-28 14:37:43 +03:00
thres = mult_frac ( bwmon_kbps_to_count ( bwmon , kbps ) ,
bwmon - > data - > sample_ms , MSEC_PER_SEC ) ;
2022-07-28 14:37:44 +03:00
regmap_field_write ( reg , thres ) ;
2022-07-04 15:17:28 +03:00
}
2022-07-28 14:37:41 +03:00
static void bwmon_start ( struct icc_bwmon * bwmon )
2022-07-04 15:17:28 +03:00
{
2022-07-28 14:37:41 +03:00
const struct icc_bwmon_data * data = bwmon - > data ;
2022-07-04 15:17:28 +03:00
int window ;
2022-07-28 14:37:42 +03:00
bwmon_clear_counters ( bwmon , true ) ;
2022-07-04 15:17:28 +03:00
2022-07-28 14:37:41 +03:00
window = mult_frac ( bwmon - > data - > sample_ms , HW_TIMER_HZ , MSEC_PER_SEC ) ;
2022-07-28 14:37:46 +03:00
/* Maximum sampling window: 0xffffff for v4 and 0xfffff for v5 */
2022-07-28 14:37:44 +03:00
regmap_field_write ( bwmon - > regs [ F_SAMPLE_WINDOW ] , window ) ;
2022-07-04 15:17:28 +03:00
2022-07-28 14:37:44 +03:00
bwmon_set_threshold ( bwmon , bwmon - > regs [ F_THRESHOLD_HIGH ] ,
2022-07-04 15:17:28 +03:00
data - > default_highbw_kbps ) ;
2022-07-28 14:37:44 +03:00
bwmon_set_threshold ( bwmon , bwmon - > regs [ F_THRESHOLD_MED ] ,
2022-07-04 15:17:28 +03:00
data - > default_medbw_kbps ) ;
2022-07-28 14:37:44 +03:00
bwmon_set_threshold ( bwmon , bwmon - > regs [ F_THRESHOLD_LOW ] ,
2022-07-04 15:17:28 +03:00
data - > default_lowbw_kbps ) ;
2022-07-28 14:37:44 +03:00
regmap_field_write ( bwmon - > regs [ F_THRESHOLD_COUNT_ZONE0 ] ,
BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT ) ;
regmap_field_write ( bwmon - > regs [ F_THRESHOLD_COUNT_ZONE1 ] ,
data - > zone1_thres_count ) ;
regmap_field_write ( bwmon - > regs [ F_THRESHOLD_COUNT_ZONE2 ] ,
BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT ) ;
regmap_field_write ( bwmon - > regs [ F_THRESHOLD_COUNT_ZONE3 ] ,
data - > zone3_thres_count ) ;
regmap_field_write ( bwmon - > regs [ F_ZONE_ACTIONS_ZONE0 ] ,
BWMON_ZONE_ACTIONS_ZONE0 ) ;
regmap_field_write ( bwmon - > regs [ F_ZONE_ACTIONS_ZONE1 ] ,
BWMON_ZONE_ACTIONS_ZONE1 ) ;
regmap_field_write ( bwmon - > regs [ F_ZONE_ACTIONS_ZONE2 ] ,
BWMON_ZONE_ACTIONS_ZONE2 ) ;
regmap_field_write ( bwmon - > regs [ F_ZONE_ACTIONS_ZONE3 ] ,
BWMON_ZONE_ACTIONS_ZONE3 ) ;
2022-07-04 15:17:28 +03:00
bwmon_clear_irq ( bwmon ) ;
bwmon_enable ( bwmon , BWMON_IRQ_ENABLE_MASK ) ;
}
static irqreturn_t bwmon_intr ( int irq , void * dev_id )
{
struct icc_bwmon * bwmon = dev_id ;
unsigned int status , max ;
int zone ;
2022-07-28 14:37:44 +03:00
if ( regmap_field_read ( bwmon - > regs [ F_IRQ_STATUS ] , & status ) )
return IRQ_NONE ;
2022-07-04 15:17:28 +03:00
status & = BWMON_IRQ_ENABLE_MASK ;
if ( ! status ) {
/*
* Only zone 1 and zone 3 interrupts are enabled but zone 2
* threshold could be hit and trigger interrupt even if not
* enabled .
* Such spurious interrupt might come with valuable max count or
* not , so solution would be to always check all
* BWMON_ZONE_MAX ( ) registers to find the highest value .
* Such case is currently ignored .
*/
return IRQ_NONE ;
}
bwmon_disable ( bwmon ) ;
2022-07-28 14:37:44 +03:00
zone = get_bitmask_order ( status ) - 1 ;
2022-07-04 15:17:28 +03:00
/*
* Zone max bytes count register returns count units within sampling
* window . Downstream kernel for BWMONv4 ( called BWMON type 2 in
* downstream ) always increments the max bytes count by one .
*/
2022-07-28 14:37:44 +03:00
if ( regmap_field_read ( bwmon - > regs [ F_ZONE0_MAX + zone ] , & max ) )
return IRQ_NONE ;
max + = 1 ;
2022-07-28 14:37:43 +03:00
max * = bwmon - > data - > count_unit_kb ;
2022-07-28 14:37:41 +03:00
bwmon - > target_kbps = mult_frac ( max , MSEC_PER_SEC , bwmon - > data - > sample_ms ) ;
2022-07-04 15:17:28 +03:00
return IRQ_WAKE_THREAD ;
}
static irqreturn_t bwmon_intr_thread ( int irq , void * dev_id )
{
struct icc_bwmon * bwmon = dev_id ;
unsigned int irq_enable = 0 ;
struct dev_pm_opp * opp , * target_opp ;
unsigned int bw_kbps , up_kbps , down_kbps ;
bw_kbps = bwmon - > target_kbps ;
target_opp = dev_pm_opp_find_bw_ceil ( bwmon - > dev , & bw_kbps , 0 ) ;
if ( IS_ERR ( target_opp ) & & PTR_ERR ( target_opp ) = = - ERANGE )
target_opp = dev_pm_opp_find_bw_floor ( bwmon - > dev , & bw_kbps , 0 ) ;
bwmon - > target_kbps = bw_kbps ;
bw_kbps - - ;
opp = dev_pm_opp_find_bw_floor ( bwmon - > dev , & bw_kbps , 0 ) ;
if ( IS_ERR ( opp ) & & PTR_ERR ( opp ) = = - ERANGE )
down_kbps = bwmon - > target_kbps ;
else
down_kbps = bw_kbps ;
up_kbps = bwmon - > target_kbps + 1 ;
if ( bwmon - > target_kbps > = bwmon - > max_bw_kbps )
2022-07-28 14:37:44 +03:00
irq_enable = BIT ( 1 ) ;
2022-07-04 15:17:28 +03:00
else if ( bwmon - > target_kbps < = bwmon - > min_bw_kbps )
2022-07-28 14:37:44 +03:00
irq_enable = BIT ( 3 ) ;
2022-07-04 15:17:28 +03:00
else
irq_enable = BWMON_IRQ_ENABLE_MASK ;
2022-07-28 14:37:44 +03:00
bwmon_set_threshold ( bwmon , bwmon - > regs [ F_THRESHOLD_HIGH ] ,
up_kbps ) ;
bwmon_set_threshold ( bwmon , bwmon - > regs [ F_THRESHOLD_MED ] ,
down_kbps ) ;
2022-07-28 14:37:42 +03:00
bwmon_clear_counters ( bwmon , false ) ;
2022-07-04 15:17:28 +03:00
bwmon_clear_irq ( bwmon ) ;
bwmon_enable ( bwmon , irq_enable ) ;
if ( bwmon - > target_kbps = = bwmon - > current_kbps )
goto out ;
dev_pm_opp_set_opp ( bwmon - > dev , target_opp ) ;
bwmon - > current_kbps = bwmon - > target_kbps ;
out :
dev_pm_opp_put ( target_opp ) ;
if ( ! IS_ERR ( opp ) )
dev_pm_opp_put ( opp ) ;
return IRQ_HANDLED ;
}
2022-07-28 14:37:44 +03:00
static int bwmon_init_regmap ( struct platform_device * pdev ,
struct icc_bwmon * bwmon )
{
struct device * dev = & pdev - > dev ;
void __iomem * base ;
struct regmap * map ;
2023-03-15 17:11:21 +03:00
int ret ;
2022-07-28 14:37:44 +03:00
2023-03-15 17:11:21 +03:00
/* Map the monitor base */
2022-07-28 14:37:44 +03:00
base = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( base ) )
return dev_err_probe ( dev , PTR_ERR ( base ) ,
" failed to map bwmon registers \n " ) ;
map = devm_regmap_init_mmio ( dev , base , bwmon - > data - > regmap_cfg ) ;
if ( IS_ERR ( map ) )
return dev_err_probe ( dev , PTR_ERR ( map ) ,
" failed to initialize regmap \n " ) ;
2023-03-15 17:11:21 +03:00
BUILD_BUG_ON ( ARRAY_SIZE ( msm8998_bwmon_global_reg_fields ) ! = F_NUM_GLOBAL_FIELDS ) ;
2022-07-28 14:37:44 +03:00
BUILD_BUG_ON ( ARRAY_SIZE ( msm8998_bwmon_reg_fields ) ! = F_NUM_FIELDS ) ;
2023-03-15 17:11:21 +03:00
BUILD_BUG_ON ( ARRAY_SIZE ( sdm845_cpu_bwmon_reg_fields ) ! = F_NUM_FIELDS ) ;
2022-07-28 14:37:46 +03:00
BUILD_BUG_ON ( ARRAY_SIZE ( sdm845_llcc_bwmon_reg_fields ) ! = F_NUM_FIELDS ) ;
2022-08-23 16:36:20 +03:00
2023-03-15 17:11:21 +03:00
ret = devm_regmap_field_bulk_alloc ( dev , map , bwmon - > regs ,
2022-07-28 14:37:44 +03:00
bwmon - > data - > regmap_fields ,
F_NUM_FIELDS ) ;
2023-03-15 17:11:21 +03:00
if ( ret )
return ret ;
if ( bwmon - > data - > global_regmap_cfg ) {
/* Map the global base, if separate */
base = devm_platform_ioremap_resource ( pdev , 1 ) ;
if ( IS_ERR ( base ) )
return dev_err_probe ( dev , PTR_ERR ( base ) ,
" failed to map bwmon global registers \n " ) ;
map = devm_regmap_init_mmio ( dev , base , bwmon - > data - > global_regmap_cfg ) ;
if ( IS_ERR ( map ) )
return dev_err_probe ( dev , PTR_ERR ( map ) ,
" failed to initialize global regmap \n " ) ;
ret = devm_regmap_field_bulk_alloc ( dev , map , bwmon - > global_regs ,
bwmon - > data - > global_regmap_fields ,
F_NUM_GLOBAL_FIELDS ) ;
}
return ret ;
2022-07-28 14:37:44 +03:00
}
2022-07-04 15:17:28 +03:00
static int bwmon_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct dev_pm_opp * opp ;
struct icc_bwmon * bwmon ;
int ret ;
bwmon = devm_kzalloc ( dev , sizeof ( * bwmon ) , GFP_KERNEL ) ;
if ( ! bwmon )
return - ENOMEM ;
2022-07-28 14:37:41 +03:00
bwmon - > data = of_device_get_match_data ( dev ) ;
2022-07-04 15:17:28 +03:00
2022-07-28 14:37:44 +03:00
ret = bwmon_init_regmap ( pdev , bwmon ) ;
if ( ret )
return ret ;
2022-07-04 15:17:28 +03:00
bwmon - > irq = platform_get_irq ( pdev , 0 ) ;
2022-07-14 10:55:32 +03:00
if ( bwmon - > irq < 0 )
2022-07-04 15:17:28 +03:00
return bwmon - > irq ;
ret = devm_pm_opp_of_add_table ( dev ) ;
if ( ret )
return dev_err_probe ( dev , ret , " failed to add OPP table \n " ) ;
bwmon - > max_bw_kbps = UINT_MAX ;
opp = dev_pm_opp_find_bw_floor ( dev , & bwmon - > max_bw_kbps , 0 ) ;
if ( IS_ERR ( opp ) )
return dev_err_probe ( dev , ret , " failed to find max peak bandwidth \n " ) ;
bwmon - > min_bw_kbps = 0 ;
opp = dev_pm_opp_find_bw_ceil ( dev , & bwmon - > min_bw_kbps , 0 ) ;
if ( IS_ERR ( opp ) )
return dev_err_probe ( dev , ret , " failed to find min peak bandwidth \n " ) ;
bwmon - > dev = dev ;
bwmon_disable ( bwmon ) ;
ret = devm_request_threaded_irq ( dev , bwmon - > irq , bwmon_intr ,
bwmon_intr_thread ,
IRQF_ONESHOT , dev_name ( dev ) , bwmon ) ;
if ( ret )
return dev_err_probe ( dev , ret , " failed to request IRQ \n " ) ;
platform_set_drvdata ( pdev , bwmon ) ;
2022-07-28 14:37:41 +03:00
bwmon_start ( bwmon ) ;
2022-07-04 15:17:28 +03:00
return 0 ;
}
static int bwmon_remove ( struct platform_device * pdev )
{
struct icc_bwmon * bwmon = platform_get_drvdata ( pdev ) ;
bwmon_disable ( bwmon ) ;
return 0 ;
}
static const struct icc_bwmon_data msm8998_bwmon_data = {
. sample_ms = 4 ,
2022-07-28 14:37:43 +03:00
. count_unit_kb = 64 ,
2022-07-04 15:17:28 +03:00
. default_highbw_kbps = 4800 * 1024 , /* 4.8 GBps */
. default_medbw_kbps = 512 * 1024 , /* 512 MBps */
. default_lowbw_kbps = 0 ,
. zone1_thres_count = 16 ,
. zone3_thres_count = 1 ,
2022-07-28 14:37:45 +03:00
. quirks = BWMON_HAS_GLOBAL_IRQ ,
2022-07-28 14:37:44 +03:00
. regmap_fields = msm8998_bwmon_reg_fields ,
. regmap_cfg = & msm8998_bwmon_regmap_cfg ,
2023-03-15 17:11:21 +03:00
. global_regmap_fields = msm8998_bwmon_global_reg_fields ,
. global_regmap_cfg = & msm8998_bwmon_global_regmap_cfg ,
} ;
static const struct icc_bwmon_data sdm845_cpu_bwmon_data = {
. sample_ms = 4 ,
. count_unit_kb = 64 ,
. default_highbw_kbps = 4800 * 1024 , /* 4.8 GBps */
. default_medbw_kbps = 512 * 1024 , /* 512 MBps */
. default_lowbw_kbps = 0 ,
. zone1_thres_count = 16 ,
. zone3_thres_count = 1 ,
. quirks = BWMON_HAS_GLOBAL_IRQ ,
. regmap_fields = sdm845_cpu_bwmon_reg_fields ,
. regmap_cfg = & sdm845_cpu_bwmon_regmap_cfg ,
2022-07-04 15:17:28 +03:00
} ;
2022-07-28 14:37:46 +03:00
static const struct icc_bwmon_data sdm845_llcc_bwmon_data = {
. sample_ms = 4 ,
. count_unit_kb = 1024 ,
. default_highbw_kbps = 800 * 1024 , /* 800 MBps */
. default_medbw_kbps = 256 * 1024 , /* 256 MBps */
. default_lowbw_kbps = 0 ,
. zone1_thres_count = 16 ,
. zone3_thres_count = 1 ,
. regmap_fields = sdm845_llcc_bwmon_reg_fields ,
. regmap_cfg = & sdm845_llcc_bwmon_regmap_cfg ,
} ;
2022-09-02 07:35:09 +03:00
static const struct icc_bwmon_data sc7280_llcc_bwmon_data = {
. sample_ms = 4 ,
. count_unit_kb = 64 ,
. default_highbw_kbps = 800 * 1024 , /* 800 MBps */
. default_medbw_kbps = 256 * 1024 , /* 256 MBps */
. default_lowbw_kbps = 0 ,
. zone1_thres_count = 16 ,
. zone3_thres_count = 1 ,
2022-09-02 07:35:10 +03:00
. quirks = BWMON_NEEDS_FORCE_CLEAR ,
2022-09-02 07:35:09 +03:00
. regmap_fields = sdm845_llcc_bwmon_reg_fields ,
. regmap_cfg = & sdm845_llcc_bwmon_regmap_cfg ,
} ;
2022-07-04 15:17:28 +03:00
static const struct of_device_id bwmon_of_match [ ] = {
2023-03-15 17:11:21 +03:00
/* BWMONv4, separate monitor and global register spaces */
{ . compatible = " qcom,msm8998-bwmon " , . data = & msm8998_bwmon_data } ,
/* BWMONv4, unified register space */
{ . compatible = " qcom,sdm845-bwmon " , . data = & sdm845_cpu_bwmon_data } ,
/* BWMONv5 */
{ . compatible = " qcom,sdm845-llcc-bwmon " , . data = & sdm845_llcc_bwmon_data } ,
{ . compatible = " qcom,sc7280-llcc-bwmon " , . data = & sc7280_llcc_bwmon_data } ,
/* Compatibles kept for legacy reasons */
{ . compatible = " qcom,sc7280-cpu-bwmon " , . data = & sdm845_cpu_bwmon_data } ,
{ . compatible = " qcom,sc8280xp-cpu-bwmon " , . data = & sdm845_cpu_bwmon_data } ,
{ . compatible = " qcom,sm8550-cpu-bwmon " , . data = & sdm845_cpu_bwmon_data } ,
2022-07-04 15:17:28 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , bwmon_of_match ) ;
static struct platform_driver bwmon_driver = {
. probe = bwmon_probe ,
. remove = bwmon_remove ,
. driver = {
. name = " qcom-bwmon " ,
. of_match_table = bwmon_of_match ,
} ,
} ;
module_platform_driver ( bwmon_driver ) ;
MODULE_AUTHOR ( " Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> " ) ;
MODULE_DESCRIPTION ( " QCOM BWMON driver " ) ;
MODULE_LICENSE ( " GPL " ) ;