1b9c2ae6cSKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0-only 2b9c2ae6cSKrzysztof Kozlowski /* 3b9c2ae6cSKrzysztof Kozlowski * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. 4b9c2ae6cSKrzysztof Kozlowski * Copyright (C) 2021-2022 Linaro Ltd 5b9c2ae6cSKrzysztof Kozlowski * Author: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>, based on 6b9c2ae6cSKrzysztof Kozlowski * previous work of Thara Gopinath and msm-4.9 downstream sources. 7b9c2ae6cSKrzysztof Kozlowski */ 8ec63dcd3SKrzysztof Kozlowski 9ec63dcd3SKrzysztof Kozlowski #include <linux/err.h> 10b9c2ae6cSKrzysztof Kozlowski #include <linux/interconnect.h> 11b9c2ae6cSKrzysztof Kozlowski #include <linux/interrupt.h> 12b9c2ae6cSKrzysztof Kozlowski #include <linux/io.h> 13b9c2ae6cSKrzysztof Kozlowski #include <linux/kernel.h> 14b9c2ae6cSKrzysztof Kozlowski #include <linux/module.h> 15b9c2ae6cSKrzysztof Kozlowski #include <linux/of_device.h> 16b9c2ae6cSKrzysztof Kozlowski #include <linux/platform_device.h> 17b9c2ae6cSKrzysztof Kozlowski #include <linux/pm_opp.h> 18ec63dcd3SKrzysztof Kozlowski #include <linux/regmap.h> 19b9c2ae6cSKrzysztof Kozlowski #include <linux/sizes.h> 20b9c2ae6cSKrzysztof Kozlowski 21b9c2ae6cSKrzysztof Kozlowski /* 22b9c2ae6cSKrzysztof Kozlowski * The BWMON samples data throughput within 'sample_ms' time. With three 23b9c2ae6cSKrzysztof Kozlowski * configurable thresholds (Low, Medium and High) gives four windows (called 24b9c2ae6cSKrzysztof Kozlowski * zones) of current bandwidth: 25b9c2ae6cSKrzysztof Kozlowski * 26b9c2ae6cSKrzysztof Kozlowski * Zone 0: byte count < THRES_LO 27b9c2ae6cSKrzysztof Kozlowski * Zone 1: THRES_LO < byte count < THRES_MED 28b9c2ae6cSKrzysztof Kozlowski * Zone 2: THRES_MED < byte count < THRES_HIGH 29b9c2ae6cSKrzysztof Kozlowski * Zone 3: THRES_HIGH < byte count 30b9c2ae6cSKrzysztof Kozlowski * 31b9c2ae6cSKrzysztof Kozlowski * Zones 0 and 2 are not used by this driver. 32b9c2ae6cSKrzysztof Kozlowski */ 33b9c2ae6cSKrzysztof Kozlowski 34b9c2ae6cSKrzysztof Kozlowski /* Internal sampling clock frequency */ 35b9c2ae6cSKrzysztof Kozlowski #define HW_TIMER_HZ 19200000 36b9c2ae6cSKrzysztof Kozlowski 37b6e9fb7aSKonrad Dybcio #define BWMON_V4_GLOBAL_IRQ_CLEAR 0x108 38b6e9fb7aSKonrad Dybcio #define BWMON_V4_GLOBAL_IRQ_ENABLE 0x10c 39ec63dcd3SKrzysztof Kozlowski /* 40ec63dcd3SKrzysztof Kozlowski * All values here and further are matching regmap fields, so without absolute 41ec63dcd3SKrzysztof Kozlowski * register offsets. 42ec63dcd3SKrzysztof Kozlowski */ 43ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE BIT(0) 44b9c2ae6cSKrzysztof Kozlowski 45b6e9fb7aSKonrad Dybcio /* 46b6e9fb7aSKonrad Dybcio * Starting with SDM845, the BWMON4 register space has changed a bit: 47b6e9fb7aSKonrad Dybcio * the global registers were jammed into the beginning of the monitor region. 48b6e9fb7aSKonrad Dybcio * To keep the proper offsets, one would have to map <GLOBAL_BASE 0x200> and 49b6e9fb7aSKonrad Dybcio * <GLOBAL_BASE+0x100 0x300>, which is straight up wrong. 50b6e9fb7aSKonrad Dybcio * To facilitate for that, while allowing the older, arguably more proper 51b6e9fb7aSKonrad Dybcio * implementations to work, offset the global registers by -0x100 to avoid 52b6e9fb7aSKonrad Dybcio * having to map half of the global registers twice. 53b6e9fb7aSKonrad Dybcio */ 54b6e9fb7aSKonrad Dybcio #define BWMON_V4_845_OFFSET 0x100 55b6e9fb7aSKonrad Dybcio #define BWMON_V4_GLOBAL_IRQ_CLEAR_845 (BWMON_V4_GLOBAL_IRQ_CLEAR - BWMON_V4_845_OFFSET) 56b6e9fb7aSKonrad Dybcio #define BWMON_V4_GLOBAL_IRQ_ENABLE_845 (BWMON_V4_GLOBAL_IRQ_ENABLE - BWMON_V4_845_OFFSET) 57b6e9fb7aSKonrad Dybcio 58ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_IRQ_STATUS 0x100 59ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_IRQ_CLEAR 0x108 60b9c2ae6cSKrzysztof Kozlowski 61ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_IRQ_ENABLE 0x10c 62ec63dcd3SKrzysztof Kozlowski #define BWMON_IRQ_ENABLE_MASK (BIT(1) | BIT(3)) 6314af4ce0SKrzysztof Kozlowski #define BWMON_V5_IRQ_STATUS 0x000 6414af4ce0SKrzysztof Kozlowski #define BWMON_V5_IRQ_CLEAR 0x008 6514af4ce0SKrzysztof Kozlowski #define BWMON_V5_IRQ_ENABLE 0x00c 66ec63dcd3SKrzysztof Kozlowski 67ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_ENABLE 0x2a0 6814af4ce0SKrzysztof Kozlowski #define BWMON_V5_ENABLE 0x010 69b9c2ae6cSKrzysztof Kozlowski #define BWMON_ENABLE_ENABLE BIT(0) 70b9c2ae6cSKrzysztof Kozlowski 71ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_CLEAR 0x2a4 7214af4ce0SKrzysztof Kozlowski #define BWMON_V5_CLEAR 0x014 73b9c2ae6cSKrzysztof Kozlowski #define BWMON_CLEAR_CLEAR BIT(0) 74956deab5SKrzysztof Kozlowski #define BWMON_CLEAR_CLEAR_ALL BIT(1) 75b9c2ae6cSKrzysztof Kozlowski 76ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_SAMPLE_WINDOW 0x2a8 7714af4ce0SKrzysztof Kozlowski #define BWMON_V5_SAMPLE_WINDOW 0x020 7814af4ce0SKrzysztof Kozlowski 79ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_HIGH 0x2ac 80ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_MED 0x2b0 81ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_LOW 0x2b4 8214af4ce0SKrzysztof Kozlowski #define BWMON_V5_THRESHOLD_HIGH 0x024 8314af4ce0SKrzysztof Kozlowski #define BWMON_V5_THRESHOLD_MED 0x028 8414af4ce0SKrzysztof Kozlowski #define BWMON_V5_THRESHOLD_LOW 0x02c 85b9c2ae6cSKrzysztof Kozlowski 86ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_ZONE_ACTIONS 0x2b8 8714af4ce0SKrzysztof Kozlowski #define BWMON_V5_ZONE_ACTIONS 0x030 88b9c2ae6cSKrzysztof Kozlowski /* 89b9c2ae6cSKrzysztof Kozlowski * Actions to perform on some zone 'z' when current zone hits the threshold: 90b9c2ae6cSKrzysztof Kozlowski * Increment counter of zone 'z' 91b9c2ae6cSKrzysztof Kozlowski */ 92b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_INCREMENT(z) (0x2 << ((z) * 2)) 93b9c2ae6cSKrzysztof Kozlowski /* Clear counter of zone 'z' */ 94b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_CLEAR(z) (0x1 << ((z) * 2)) 95b9c2ae6cSKrzysztof Kozlowski 96b9c2ae6cSKrzysztof Kozlowski /* Zone 0 threshold hit: Clear zone count */ 97b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE0 (BWMON_ZONE_ACTIONS_CLEAR(0)) 98b9c2ae6cSKrzysztof Kozlowski 99b9c2ae6cSKrzysztof Kozlowski /* Zone 1 threshold hit: Increment zone count & clear lower zones */ 100b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE1 (BWMON_ZONE_ACTIONS_INCREMENT(1) | \ 101b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(0)) 102b9c2ae6cSKrzysztof Kozlowski 103b9c2ae6cSKrzysztof Kozlowski /* Zone 2 threshold hit: Increment zone count & clear lower zones */ 104b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE2 (BWMON_ZONE_ACTIONS_INCREMENT(2) | \ 105b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(1) | \ 106b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(0)) 107b9c2ae6cSKrzysztof Kozlowski 108b9c2ae6cSKrzysztof Kozlowski /* Zone 3 threshold hit: Increment zone count & clear lower zones */ 109b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE3 (BWMON_ZONE_ACTIONS_INCREMENT(3) | \ 110b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(2) | \ 111b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(1) | \ 112b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(0)) 113b9c2ae6cSKrzysztof Kozlowski 114b9c2ae6cSKrzysztof Kozlowski /* 115ec63dcd3SKrzysztof Kozlowski * There is no clear documentation/explanation of BWMON_V4_THRESHOLD_COUNT 116b9c2ae6cSKrzysztof Kozlowski * register. Based on observations, this is number of times one threshold has to 117b9c2ae6cSKrzysztof Kozlowski * be reached, to trigger interrupt in given zone. 118b9c2ae6cSKrzysztof Kozlowski * 119b9c2ae6cSKrzysztof Kozlowski * 0xff are maximum values meant to ignore the zones 0 and 2. 120b9c2ae6cSKrzysztof Kozlowski */ 121ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_COUNT 0x2bc 12214af4ce0SKrzysztof Kozlowski #define BWMON_V5_THRESHOLD_COUNT 0x034 123b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT 0xff 124b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT 0xff 125b9c2ae6cSKrzysztof Kozlowski 126ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_ZONE_MAX(zone) (0x2e0 + 4 * (zone)) 12714af4ce0SKrzysztof Kozlowski #define BWMON_V5_ZONE_MAX(zone) (0x044 + 4 * (zone)) 128ec63dcd3SKrzysztof Kozlowski 129e6f34184SKrzysztof Kozlowski /* Quirks for specific BWMON types */ 130e6f34184SKrzysztof Kozlowski #define BWMON_HAS_GLOBAL_IRQ BIT(0) 131cdad59c2SRajendra Nayak #define BWMON_NEEDS_FORCE_CLEAR BIT(1) 132e6f34184SKrzysztof Kozlowski 133ec63dcd3SKrzysztof Kozlowski enum bwmon_fields { 134b6e9fb7aSKonrad Dybcio /* Global region fields, keep them at the top */ 135ec63dcd3SKrzysztof Kozlowski F_GLOBAL_IRQ_CLEAR, 136ec63dcd3SKrzysztof Kozlowski F_GLOBAL_IRQ_ENABLE, 137b6e9fb7aSKonrad Dybcio F_NUM_GLOBAL_FIELDS, 138b6e9fb7aSKonrad Dybcio 139b6e9fb7aSKonrad Dybcio /* Monitor region fields */ 140b6e9fb7aSKonrad Dybcio F_IRQ_STATUS = F_NUM_GLOBAL_FIELDS, 141ec63dcd3SKrzysztof Kozlowski F_IRQ_CLEAR, 142ec63dcd3SKrzysztof Kozlowski F_IRQ_ENABLE, 143ec63dcd3SKrzysztof Kozlowski F_ENABLE, 144ec63dcd3SKrzysztof Kozlowski F_CLEAR, 145ec63dcd3SKrzysztof Kozlowski F_SAMPLE_WINDOW, 146ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_HIGH, 147ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_MED, 148ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_LOW, 149ec63dcd3SKrzysztof Kozlowski F_ZONE_ACTIONS_ZONE0, 150ec63dcd3SKrzysztof Kozlowski F_ZONE_ACTIONS_ZONE1, 151ec63dcd3SKrzysztof Kozlowski F_ZONE_ACTIONS_ZONE2, 152ec63dcd3SKrzysztof Kozlowski F_ZONE_ACTIONS_ZONE3, 153ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_COUNT_ZONE0, 154ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_COUNT_ZONE1, 155ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_COUNT_ZONE2, 156ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_COUNT_ZONE3, 157ec63dcd3SKrzysztof Kozlowski F_ZONE0_MAX, 158ec63dcd3SKrzysztof Kozlowski F_ZONE1_MAX, 159ec63dcd3SKrzysztof Kozlowski F_ZONE2_MAX, 160ec63dcd3SKrzysztof Kozlowski F_ZONE3_MAX, 161ec63dcd3SKrzysztof Kozlowski 162ec63dcd3SKrzysztof Kozlowski F_NUM_FIELDS 163ec63dcd3SKrzysztof Kozlowski }; 164b9c2ae6cSKrzysztof Kozlowski 165b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon_data { 166b9c2ae6cSKrzysztof Kozlowski unsigned int sample_ms; 167650db9faSKrzysztof Kozlowski unsigned int count_unit_kb; /* kbytes */ 168b9c2ae6cSKrzysztof Kozlowski unsigned int default_highbw_kbps; 169b9c2ae6cSKrzysztof Kozlowski unsigned int default_medbw_kbps; 170b9c2ae6cSKrzysztof Kozlowski unsigned int default_lowbw_kbps; 171b9c2ae6cSKrzysztof Kozlowski u8 zone1_thres_count; 172b9c2ae6cSKrzysztof Kozlowski u8 zone3_thres_count; 173e6f34184SKrzysztof Kozlowski unsigned int quirks; 174ec63dcd3SKrzysztof Kozlowski 175ec63dcd3SKrzysztof Kozlowski const struct regmap_config *regmap_cfg; 176ec63dcd3SKrzysztof Kozlowski const struct reg_field *regmap_fields; 177b6e9fb7aSKonrad Dybcio 178b6e9fb7aSKonrad Dybcio const struct regmap_config *global_regmap_cfg; 179b6e9fb7aSKonrad Dybcio const struct reg_field *global_regmap_fields; 180b9c2ae6cSKrzysztof Kozlowski }; 181b9c2ae6cSKrzysztof Kozlowski 182b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon { 183b9c2ae6cSKrzysztof Kozlowski struct device *dev; 1841dd5246eSKrzysztof Kozlowski const struct icc_bwmon_data *data; 185b9c2ae6cSKrzysztof Kozlowski int irq; 186b9c2ae6cSKrzysztof Kozlowski 187ec63dcd3SKrzysztof Kozlowski struct regmap_field *regs[F_NUM_FIELDS]; 188b6e9fb7aSKonrad Dybcio struct regmap_field *global_regs[F_NUM_GLOBAL_FIELDS]; 189ec63dcd3SKrzysztof Kozlowski 190b9c2ae6cSKrzysztof Kozlowski unsigned int max_bw_kbps; 191b9c2ae6cSKrzysztof Kozlowski unsigned int min_bw_kbps; 192b9c2ae6cSKrzysztof Kozlowski unsigned int target_kbps; 193b9c2ae6cSKrzysztof Kozlowski unsigned int current_kbps; 194b9c2ae6cSKrzysztof Kozlowski }; 195b9c2ae6cSKrzysztof Kozlowski 196ec63dcd3SKrzysztof Kozlowski /* BWMON v4 */ 197ec63dcd3SKrzysztof Kozlowski static const struct reg_field msm8998_bwmon_reg_fields[] = { 198b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_CLEAR] = {}, 199b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_ENABLE] = {}, 200ec63dcd3SKrzysztof Kozlowski [F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7), 201ec63dcd3SKrzysztof Kozlowski [F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7), 202ec63dcd3SKrzysztof Kozlowski [F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7), 203ec63dcd3SKrzysztof Kozlowski /* F_ENABLE covers entire register to disable other features */ 204ec63dcd3SKrzysztof Kozlowski [F_ENABLE] = REG_FIELD(BWMON_V4_ENABLE, 0, 31), 205ec63dcd3SKrzysztof Kozlowski [F_CLEAR] = REG_FIELD(BWMON_V4_CLEAR, 0, 1), 206ec63dcd3SKrzysztof Kozlowski [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23), 207ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11), 208ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_MED] = REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11), 209ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11), 210ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7), 211ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15), 212ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23), 213ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31), 214ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7), 215ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15), 216ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23), 217ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31), 218ec63dcd3SKrzysztof Kozlowski [F_ZONE0_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11), 219ec63dcd3SKrzysztof Kozlowski [F_ZONE1_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11), 220ec63dcd3SKrzysztof Kozlowski [F_ZONE2_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11), 221ec63dcd3SKrzysztof Kozlowski [F_ZONE3_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11), 222ec63dcd3SKrzysztof Kozlowski }; 223ec63dcd3SKrzysztof Kozlowski 224ec63dcd3SKrzysztof Kozlowski static const struct regmap_range msm8998_bwmon_reg_noread_ranges[] = { 225ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR), 226ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR), 227ec63dcd3SKrzysztof Kozlowski }; 228ec63dcd3SKrzysztof Kozlowski 229ec63dcd3SKrzysztof Kozlowski static const struct regmap_access_table msm8998_bwmon_reg_read_table = { 230ec63dcd3SKrzysztof Kozlowski .no_ranges = msm8998_bwmon_reg_noread_ranges, 231ec63dcd3SKrzysztof Kozlowski .n_no_ranges = ARRAY_SIZE(msm8998_bwmon_reg_noread_ranges), 232ec63dcd3SKrzysztof Kozlowski }; 233ec63dcd3SKrzysztof Kozlowski 234ec63dcd3SKrzysztof Kozlowski static const struct regmap_range msm8998_bwmon_reg_volatile_ranges[] = { 235ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_IRQ_STATUS, BWMON_V4_IRQ_STATUS), 236ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_ZONE_MAX(0), BWMON_V4_ZONE_MAX(3)), 237ec63dcd3SKrzysztof Kozlowski }; 238ec63dcd3SKrzysztof Kozlowski 239ec63dcd3SKrzysztof Kozlowski static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = { 240ec63dcd3SKrzysztof Kozlowski .yes_ranges = msm8998_bwmon_reg_volatile_ranges, 241ec63dcd3SKrzysztof Kozlowski .n_yes_ranges = ARRAY_SIZE(msm8998_bwmon_reg_volatile_ranges), 242ec63dcd3SKrzysztof Kozlowski }; 243ec63dcd3SKrzysztof Kozlowski 244b6e9fb7aSKonrad Dybcio static const struct reg_field msm8998_bwmon_global_reg_fields[] = { 245b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0), 246b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0), 247b6e9fb7aSKonrad Dybcio }; 248b6e9fb7aSKonrad Dybcio 249b6e9fb7aSKonrad Dybcio static const struct regmap_range msm8998_bwmon_global_reg_noread_ranges[] = { 250b6e9fb7aSKonrad Dybcio regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR), 251b6e9fb7aSKonrad Dybcio }; 252b6e9fb7aSKonrad Dybcio 253b6e9fb7aSKonrad Dybcio static const struct regmap_access_table msm8998_bwmon_global_reg_read_table = { 254b6e9fb7aSKonrad Dybcio .no_ranges = msm8998_bwmon_global_reg_noread_ranges, 255b6e9fb7aSKonrad Dybcio .n_no_ranges = ARRAY_SIZE(msm8998_bwmon_global_reg_noread_ranges), 256b6e9fb7aSKonrad Dybcio }; 257b6e9fb7aSKonrad Dybcio 258ec63dcd3SKrzysztof Kozlowski /* 259ec63dcd3SKrzysztof Kozlowski * Fill the cache for non-readable registers only as rest does not really 260ec63dcd3SKrzysztof Kozlowski * matter and can be read from the device. 261ec63dcd3SKrzysztof Kozlowski */ 262ec63dcd3SKrzysztof Kozlowski static const struct reg_default msm8998_bwmon_reg_defaults[] = { 263ec63dcd3SKrzysztof Kozlowski { BWMON_V4_IRQ_CLEAR, 0x0 }, 264ec63dcd3SKrzysztof Kozlowski { BWMON_V4_CLEAR, 0x0 }, 265ec63dcd3SKrzysztof Kozlowski }; 266ec63dcd3SKrzysztof Kozlowski 267b6e9fb7aSKonrad Dybcio static const struct reg_default msm8998_bwmon_global_reg_defaults[] = { 268b6e9fb7aSKonrad Dybcio { BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 }, 269b6e9fb7aSKonrad Dybcio }; 270b6e9fb7aSKonrad Dybcio 271ec63dcd3SKrzysztof Kozlowski static const struct regmap_config msm8998_bwmon_regmap_cfg = { 272ec63dcd3SKrzysztof Kozlowski .reg_bits = 32, 273ec63dcd3SKrzysztof Kozlowski .reg_stride = 4, 274ec63dcd3SKrzysztof Kozlowski .val_bits = 32, 275ec63dcd3SKrzysztof Kozlowski /* 276ec63dcd3SKrzysztof Kozlowski * No concurrent access expected - driver has one interrupt handler, 277ec63dcd3SKrzysztof Kozlowski * regmap is not shared, no driver or user-space API. 278ec63dcd3SKrzysztof Kozlowski */ 279ec63dcd3SKrzysztof Kozlowski .disable_locking = true, 280ec63dcd3SKrzysztof Kozlowski .rd_table = &msm8998_bwmon_reg_read_table, 281ec63dcd3SKrzysztof Kozlowski .volatile_table = &msm8998_bwmon_reg_volatile_table, 282ec63dcd3SKrzysztof Kozlowski .reg_defaults = msm8998_bwmon_reg_defaults, 283ec63dcd3SKrzysztof Kozlowski .num_reg_defaults = ARRAY_SIZE(msm8998_bwmon_reg_defaults), 284ec63dcd3SKrzysztof Kozlowski /* 285ec63dcd3SKrzysztof Kozlowski * Cache is necessary for using regmap fields with non-readable 286ec63dcd3SKrzysztof Kozlowski * registers. 287ec63dcd3SKrzysztof Kozlowski */ 288ec63dcd3SKrzysztof Kozlowski .cache_type = REGCACHE_RBTREE, 289ec63dcd3SKrzysztof Kozlowski }; 290ec63dcd3SKrzysztof Kozlowski 291b6e9fb7aSKonrad Dybcio static const struct regmap_config msm8998_bwmon_global_regmap_cfg = { 292b6e9fb7aSKonrad Dybcio .reg_bits = 32, 293b6e9fb7aSKonrad Dybcio .reg_stride = 4, 294b6e9fb7aSKonrad Dybcio .val_bits = 32, 295b6e9fb7aSKonrad Dybcio /* 296b6e9fb7aSKonrad Dybcio * No concurrent access expected - driver has one interrupt handler, 297b6e9fb7aSKonrad Dybcio * regmap is not shared, no driver or user-space API. 298b6e9fb7aSKonrad Dybcio */ 299b6e9fb7aSKonrad Dybcio .disable_locking = true, 300b6e9fb7aSKonrad Dybcio .rd_table = &msm8998_bwmon_global_reg_read_table, 301b6e9fb7aSKonrad Dybcio .reg_defaults = msm8998_bwmon_global_reg_defaults, 302b6e9fb7aSKonrad Dybcio .num_reg_defaults = ARRAY_SIZE(msm8998_bwmon_global_reg_defaults), 303b6e9fb7aSKonrad Dybcio /* 304b6e9fb7aSKonrad Dybcio * Cache is necessary for using regmap fields with non-readable 305b6e9fb7aSKonrad Dybcio * registers. 306b6e9fb7aSKonrad Dybcio */ 307b6e9fb7aSKonrad Dybcio .cache_type = REGCACHE_RBTREE, 308b6e9fb7aSKonrad Dybcio }; 309b6e9fb7aSKonrad Dybcio 310b6e9fb7aSKonrad Dybcio static const struct reg_field sdm845_cpu_bwmon_reg_fields[] = { 311b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0, 0), 312b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE_845, 0, 0), 313b6e9fb7aSKonrad Dybcio [F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7), 314b6e9fb7aSKonrad Dybcio [F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7), 315b6e9fb7aSKonrad Dybcio [F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7), 316b6e9fb7aSKonrad Dybcio /* F_ENABLE covers entire register to disable other features */ 317b6e9fb7aSKonrad Dybcio [F_ENABLE] = REG_FIELD(BWMON_V4_ENABLE, 0, 31), 318b6e9fb7aSKonrad Dybcio [F_CLEAR] = REG_FIELD(BWMON_V4_CLEAR, 0, 1), 319b6e9fb7aSKonrad Dybcio [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23), 320b6e9fb7aSKonrad Dybcio [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11), 321b6e9fb7aSKonrad Dybcio [F_THRESHOLD_MED] = REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11), 322b6e9fb7aSKonrad Dybcio [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11), 323b6e9fb7aSKonrad Dybcio [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7), 324b6e9fb7aSKonrad Dybcio [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15), 325b6e9fb7aSKonrad Dybcio [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23), 326b6e9fb7aSKonrad Dybcio [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31), 327b6e9fb7aSKonrad Dybcio [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7), 328b6e9fb7aSKonrad Dybcio [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15), 329b6e9fb7aSKonrad Dybcio [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23), 330b6e9fb7aSKonrad Dybcio [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31), 331b6e9fb7aSKonrad Dybcio [F_ZONE0_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11), 332b6e9fb7aSKonrad Dybcio [F_ZONE1_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11), 333b6e9fb7aSKonrad Dybcio [F_ZONE2_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11), 334b6e9fb7aSKonrad Dybcio [F_ZONE3_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11), 335b6e9fb7aSKonrad Dybcio }; 336b6e9fb7aSKonrad Dybcio 337b6e9fb7aSKonrad Dybcio static const struct regmap_range sdm845_cpu_bwmon_reg_noread_ranges[] = { 338b6e9fb7aSKonrad Dybcio regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR_845, BWMON_V4_GLOBAL_IRQ_CLEAR_845), 339b6e9fb7aSKonrad Dybcio regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR), 340b6e9fb7aSKonrad Dybcio regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR), 341b6e9fb7aSKonrad Dybcio }; 342b6e9fb7aSKonrad Dybcio 343b6e9fb7aSKonrad Dybcio static const struct regmap_access_table sdm845_cpu_bwmon_reg_read_table = { 344b6e9fb7aSKonrad Dybcio .no_ranges = sdm845_cpu_bwmon_reg_noread_ranges, 345b6e9fb7aSKonrad Dybcio .n_no_ranges = ARRAY_SIZE(sdm845_cpu_bwmon_reg_noread_ranges), 346b6e9fb7aSKonrad Dybcio }; 347b6e9fb7aSKonrad Dybcio 348b6e9fb7aSKonrad Dybcio /* 349b6e9fb7aSKonrad Dybcio * Fill the cache for non-readable registers only as rest does not really 350b6e9fb7aSKonrad Dybcio * matter and can be read from the device. 351b6e9fb7aSKonrad Dybcio */ 352b6e9fb7aSKonrad Dybcio static const struct reg_default sdm845_cpu_bwmon_reg_defaults[] = { 353b6e9fb7aSKonrad Dybcio { BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0x0 }, 354b6e9fb7aSKonrad Dybcio { BWMON_V4_IRQ_CLEAR, 0x0 }, 355b6e9fb7aSKonrad Dybcio { BWMON_V4_CLEAR, 0x0 }, 356b6e9fb7aSKonrad Dybcio }; 357b6e9fb7aSKonrad Dybcio 358b6e9fb7aSKonrad Dybcio static const struct regmap_config sdm845_cpu_bwmon_regmap_cfg = { 359b6e9fb7aSKonrad Dybcio .reg_bits = 32, 360b6e9fb7aSKonrad Dybcio .reg_stride = 4, 361b6e9fb7aSKonrad Dybcio .val_bits = 32, 362b6e9fb7aSKonrad Dybcio /* 363b6e9fb7aSKonrad Dybcio * No concurrent access expected - driver has one interrupt handler, 364b6e9fb7aSKonrad Dybcio * regmap is not shared, no driver or user-space API. 365b6e9fb7aSKonrad Dybcio */ 366b6e9fb7aSKonrad Dybcio .disable_locking = true, 367b6e9fb7aSKonrad Dybcio .rd_table = &sdm845_cpu_bwmon_reg_read_table, 368b6e9fb7aSKonrad Dybcio .volatile_table = &msm8998_bwmon_reg_volatile_table, 369b6e9fb7aSKonrad Dybcio .reg_defaults = sdm845_cpu_bwmon_reg_defaults, 370b6e9fb7aSKonrad Dybcio .num_reg_defaults = ARRAY_SIZE(sdm845_cpu_bwmon_reg_defaults), 371b6e9fb7aSKonrad Dybcio /* 372b6e9fb7aSKonrad Dybcio * Cache is necessary for using regmap fields with non-readable 373b6e9fb7aSKonrad Dybcio * registers. 374b6e9fb7aSKonrad Dybcio */ 375b6e9fb7aSKonrad Dybcio .cache_type = REGCACHE_RBTREE, 376b6e9fb7aSKonrad Dybcio }; 377b6e9fb7aSKonrad Dybcio 37814af4ce0SKrzysztof Kozlowski /* BWMON v5 */ 37914af4ce0SKrzysztof Kozlowski static const struct reg_field sdm845_llcc_bwmon_reg_fields[] = { 38014af4ce0SKrzysztof Kozlowski [F_GLOBAL_IRQ_CLEAR] = {}, 38114af4ce0SKrzysztof Kozlowski [F_GLOBAL_IRQ_ENABLE] = {}, 38214af4ce0SKrzysztof Kozlowski [F_IRQ_STATUS] = REG_FIELD(BWMON_V5_IRQ_STATUS, 0, 3), 38314af4ce0SKrzysztof Kozlowski [F_IRQ_CLEAR] = REG_FIELD(BWMON_V5_IRQ_CLEAR, 0, 3), 38414af4ce0SKrzysztof Kozlowski [F_IRQ_ENABLE] = REG_FIELD(BWMON_V5_IRQ_ENABLE, 0, 3), 38514af4ce0SKrzysztof Kozlowski /* F_ENABLE covers entire register to disable other features */ 38614af4ce0SKrzysztof Kozlowski [F_ENABLE] = REG_FIELD(BWMON_V5_ENABLE, 0, 31), 38714af4ce0SKrzysztof Kozlowski [F_CLEAR] = REG_FIELD(BWMON_V5_CLEAR, 0, 1), 38814af4ce0SKrzysztof Kozlowski [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V5_SAMPLE_WINDOW, 0, 19), 38914af4ce0SKrzysztof Kozlowski [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V5_THRESHOLD_HIGH, 0, 11), 39014af4ce0SKrzysztof Kozlowski [F_THRESHOLD_MED] = REG_FIELD(BWMON_V5_THRESHOLD_MED, 0, 11), 39114af4ce0SKrzysztof Kozlowski [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V5_THRESHOLD_LOW, 0, 11), 39214af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 0, 7), 39314af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 8, 15), 39414af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 16, 23), 39514af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 24, 31), 39614af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 0, 7), 39714af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 8, 15), 39814af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 16, 23), 39914af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 24, 31), 40014af4ce0SKrzysztof Kozlowski [F_ZONE0_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(0), 0, 11), 40114af4ce0SKrzysztof Kozlowski [F_ZONE1_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(1), 0, 11), 40214af4ce0SKrzysztof Kozlowski [F_ZONE2_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(2), 0, 11), 40314af4ce0SKrzysztof Kozlowski [F_ZONE3_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(3), 0, 11), 40414af4ce0SKrzysztof Kozlowski }; 40514af4ce0SKrzysztof Kozlowski 40614af4ce0SKrzysztof Kozlowski static const struct regmap_range sdm845_llcc_bwmon_reg_noread_ranges[] = { 40714af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_IRQ_CLEAR, BWMON_V5_IRQ_CLEAR), 40814af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_CLEAR, BWMON_V5_CLEAR), 40914af4ce0SKrzysztof Kozlowski }; 41014af4ce0SKrzysztof Kozlowski 41114af4ce0SKrzysztof Kozlowski static const struct regmap_access_table sdm845_llcc_bwmon_reg_read_table = { 41214af4ce0SKrzysztof Kozlowski .no_ranges = sdm845_llcc_bwmon_reg_noread_ranges, 41314af4ce0SKrzysztof Kozlowski .n_no_ranges = ARRAY_SIZE(sdm845_llcc_bwmon_reg_noread_ranges), 41414af4ce0SKrzysztof Kozlowski }; 41514af4ce0SKrzysztof Kozlowski 41614af4ce0SKrzysztof Kozlowski static const struct regmap_range sdm845_llcc_bwmon_reg_volatile_ranges[] = { 41714af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_IRQ_STATUS, BWMON_V5_IRQ_STATUS), 41814af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_ZONE_MAX(0), BWMON_V5_ZONE_MAX(3)), 41914af4ce0SKrzysztof Kozlowski }; 42014af4ce0SKrzysztof Kozlowski 42114af4ce0SKrzysztof Kozlowski static const struct regmap_access_table sdm845_llcc_bwmon_reg_volatile_table = { 42214af4ce0SKrzysztof Kozlowski .yes_ranges = sdm845_llcc_bwmon_reg_volatile_ranges, 42314af4ce0SKrzysztof Kozlowski .n_yes_ranges = ARRAY_SIZE(sdm845_llcc_bwmon_reg_volatile_ranges), 42414af4ce0SKrzysztof Kozlowski }; 42514af4ce0SKrzysztof Kozlowski 42614af4ce0SKrzysztof Kozlowski /* 42714af4ce0SKrzysztof Kozlowski * Fill the cache for non-readable registers only as rest does not really 42814af4ce0SKrzysztof Kozlowski * matter and can be read from the device. 42914af4ce0SKrzysztof Kozlowski */ 43014af4ce0SKrzysztof Kozlowski static const struct reg_default sdm845_llcc_bwmon_reg_defaults[] = { 43114af4ce0SKrzysztof Kozlowski { BWMON_V5_IRQ_CLEAR, 0x0 }, 43214af4ce0SKrzysztof Kozlowski { BWMON_V5_CLEAR, 0x0 }, 43314af4ce0SKrzysztof Kozlowski }; 43414af4ce0SKrzysztof Kozlowski 43514af4ce0SKrzysztof Kozlowski static const struct regmap_config sdm845_llcc_bwmon_regmap_cfg = { 43614af4ce0SKrzysztof Kozlowski .reg_bits = 32, 43714af4ce0SKrzysztof Kozlowski .reg_stride = 4, 43814af4ce0SKrzysztof Kozlowski .val_bits = 32, 43914af4ce0SKrzysztof Kozlowski /* 44014af4ce0SKrzysztof Kozlowski * No concurrent access expected - driver has one interrupt handler, 44114af4ce0SKrzysztof Kozlowski * regmap is not shared, no driver or user-space API. 44214af4ce0SKrzysztof Kozlowski */ 44314af4ce0SKrzysztof Kozlowski .disable_locking = true, 44414af4ce0SKrzysztof Kozlowski .rd_table = &sdm845_llcc_bwmon_reg_read_table, 44514af4ce0SKrzysztof Kozlowski .volatile_table = &sdm845_llcc_bwmon_reg_volatile_table, 44614af4ce0SKrzysztof Kozlowski .reg_defaults = sdm845_llcc_bwmon_reg_defaults, 44714af4ce0SKrzysztof Kozlowski .num_reg_defaults = ARRAY_SIZE(sdm845_llcc_bwmon_reg_defaults), 44814af4ce0SKrzysztof Kozlowski /* 44914af4ce0SKrzysztof Kozlowski * Cache is necessary for using regmap fields with non-readable 45014af4ce0SKrzysztof Kozlowski * registers. 45114af4ce0SKrzysztof Kozlowski */ 45214af4ce0SKrzysztof Kozlowski .cache_type = REGCACHE_RBTREE, 45314af4ce0SKrzysztof Kozlowski }; 45414af4ce0SKrzysztof Kozlowski 455956deab5SKrzysztof Kozlowski static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all) 456b9c2ae6cSKrzysztof Kozlowski { 457956deab5SKrzysztof Kozlowski unsigned int val = BWMON_CLEAR_CLEAR; 458956deab5SKrzysztof Kozlowski 459956deab5SKrzysztof Kozlowski if (clear_all) 460956deab5SKrzysztof Kozlowski val |= BWMON_CLEAR_CLEAR_ALL; 461b9c2ae6cSKrzysztof Kozlowski /* 462b9c2ae6cSKrzysztof Kozlowski * Clear counters. The order and barriers are 463b9c2ae6cSKrzysztof Kozlowski * important. Quoting downstream Qualcomm msm-4.9 tree: 464b9c2ae6cSKrzysztof Kozlowski * 465b9c2ae6cSKrzysztof Kozlowski * The counter clear and IRQ clear bits are not in the same 4KB 466b9c2ae6cSKrzysztof Kozlowski * region. So, we need to make sure the counter clear is completed 467b9c2ae6cSKrzysztof Kozlowski * before we try to clear the IRQ or do any other counter operations. 468b9c2ae6cSKrzysztof Kozlowski */ 469ec63dcd3SKrzysztof Kozlowski regmap_field_force_write(bwmon->regs[F_CLEAR], val); 470cdad59c2SRajendra Nayak if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR) 471cdad59c2SRajendra Nayak regmap_field_force_write(bwmon->regs[F_CLEAR], 0); 472b9c2ae6cSKrzysztof Kozlowski } 473b9c2ae6cSKrzysztof Kozlowski 474b9c2ae6cSKrzysztof Kozlowski static void bwmon_clear_irq(struct icc_bwmon *bwmon) 475b9c2ae6cSKrzysztof Kozlowski { 476b6e9fb7aSKonrad Dybcio struct regmap_field *global_irq_clr; 477b6e9fb7aSKonrad Dybcio 478b6e9fb7aSKonrad Dybcio if (bwmon->data->global_regmap_fields) 479b6e9fb7aSKonrad Dybcio global_irq_clr = bwmon->global_regs[F_GLOBAL_IRQ_CLEAR]; 480b6e9fb7aSKonrad Dybcio else 481b6e9fb7aSKonrad Dybcio global_irq_clr = bwmon->regs[F_GLOBAL_IRQ_CLEAR]; 482b6e9fb7aSKonrad Dybcio 483b9c2ae6cSKrzysztof Kozlowski /* 484b9c2ae6cSKrzysztof Kozlowski * Clear zone and global interrupts. The order and barriers are 485b9c2ae6cSKrzysztof Kozlowski * important. Quoting downstream Qualcomm msm-4.9 tree: 486b9c2ae6cSKrzysztof Kozlowski * 487b9c2ae6cSKrzysztof Kozlowski * Synchronize the local interrupt clear in mon_irq_clear() 488b9c2ae6cSKrzysztof Kozlowski * with the global interrupt clear here. Otherwise, the CPU 489b9c2ae6cSKrzysztof Kozlowski * may reorder the two writes and clear the global interrupt 490b9c2ae6cSKrzysztof Kozlowski * before the local interrupt, causing the global interrupt 491b9c2ae6cSKrzysztof Kozlowski * to be retriggered by the local interrupt still being high. 492b9c2ae6cSKrzysztof Kozlowski * 493b9c2ae6cSKrzysztof Kozlowski * Similarly, because the global registers are in a different 494b9c2ae6cSKrzysztof Kozlowski * region than the local registers, we need to ensure any register 495b9c2ae6cSKrzysztof Kozlowski * writes to enable the monitor after this call are ordered with the 496b9c2ae6cSKrzysztof Kozlowski * clearing here so that local writes don't happen before the 497b9c2ae6cSKrzysztof Kozlowski * interrupt is cleared. 498b9c2ae6cSKrzysztof Kozlowski */ 499ec63dcd3SKrzysztof Kozlowski regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], BWMON_IRQ_ENABLE_MASK); 500cdad59c2SRajendra Nayak if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR) 501cdad59c2SRajendra Nayak regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], 0); 502e6f34184SKrzysztof Kozlowski if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) 503b6e9fb7aSKonrad Dybcio regmap_field_force_write(global_irq_clr, 504ec63dcd3SKrzysztof Kozlowski BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE); 505b9c2ae6cSKrzysztof Kozlowski } 506b9c2ae6cSKrzysztof Kozlowski 507b9c2ae6cSKrzysztof Kozlowski static void bwmon_disable(struct icc_bwmon *bwmon) 508b9c2ae6cSKrzysztof Kozlowski { 509b6e9fb7aSKonrad Dybcio struct regmap_field *global_irq_en; 510b6e9fb7aSKonrad Dybcio 511b6e9fb7aSKonrad Dybcio if (bwmon->data->global_regmap_fields) 512b6e9fb7aSKonrad Dybcio global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE]; 513b6e9fb7aSKonrad Dybcio else 514b6e9fb7aSKonrad Dybcio global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE]; 515b6e9fb7aSKonrad Dybcio 516b9c2ae6cSKrzysztof Kozlowski /* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */ 517e6f34184SKrzysztof Kozlowski if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) 518b6e9fb7aSKonrad Dybcio regmap_field_write(global_irq_en, 0x0); 519ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_IRQ_ENABLE], 0x0); 520b9c2ae6cSKrzysztof Kozlowski 521b9c2ae6cSKrzysztof Kozlowski /* 522b9c2ae6cSKrzysztof Kozlowski * Disable bwmon. Must happen before bwmon_clear_irq() to avoid spurious 523b9c2ae6cSKrzysztof Kozlowski * IRQ. 524b9c2ae6cSKrzysztof Kozlowski */ 525ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ENABLE], 0x0); 526b9c2ae6cSKrzysztof Kozlowski } 527b9c2ae6cSKrzysztof Kozlowski 528b9c2ae6cSKrzysztof Kozlowski static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable) 529b9c2ae6cSKrzysztof Kozlowski { 530b6e9fb7aSKonrad Dybcio struct regmap_field *global_irq_en; 531b6e9fb7aSKonrad Dybcio 532b6e9fb7aSKonrad Dybcio if (bwmon->data->global_regmap_fields) 533b6e9fb7aSKonrad Dybcio global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE]; 534b6e9fb7aSKonrad Dybcio else 535b6e9fb7aSKonrad Dybcio global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE]; 536b6e9fb7aSKonrad Dybcio 537b9c2ae6cSKrzysztof Kozlowski /* Enable interrupts */ 538e6f34184SKrzysztof Kozlowski if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) 539b6e9fb7aSKonrad Dybcio regmap_field_write(global_irq_en, 540ec63dcd3SKrzysztof Kozlowski BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE); 541b6e9fb7aSKonrad Dybcio 542ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_IRQ_ENABLE], irq_enable); 543b9c2ae6cSKrzysztof Kozlowski 544b9c2ae6cSKrzysztof Kozlowski /* Enable bwmon */ 545ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ENABLE], BWMON_ENABLE_ENABLE); 546b9c2ae6cSKrzysztof Kozlowski } 547b9c2ae6cSKrzysztof Kozlowski 548650db9faSKrzysztof Kozlowski static unsigned int bwmon_kbps_to_count(struct icc_bwmon *bwmon, 549650db9faSKrzysztof Kozlowski unsigned int kbps) 550b9c2ae6cSKrzysztof Kozlowski { 551650db9faSKrzysztof Kozlowski return kbps / bwmon->data->count_unit_kb; 552b9c2ae6cSKrzysztof Kozlowski } 553b9c2ae6cSKrzysztof Kozlowski 554ec63dcd3SKrzysztof Kozlowski static void bwmon_set_threshold(struct icc_bwmon *bwmon, 555ec63dcd3SKrzysztof Kozlowski struct regmap_field *reg, unsigned int kbps) 556b9c2ae6cSKrzysztof Kozlowski { 557b9c2ae6cSKrzysztof Kozlowski unsigned int thres; 558b9c2ae6cSKrzysztof Kozlowski 559650db9faSKrzysztof Kozlowski thres = mult_frac(bwmon_kbps_to_count(bwmon, kbps), 560650db9faSKrzysztof Kozlowski bwmon->data->sample_ms, MSEC_PER_SEC); 561ec63dcd3SKrzysztof Kozlowski regmap_field_write(reg, thres); 562b9c2ae6cSKrzysztof Kozlowski } 563b9c2ae6cSKrzysztof Kozlowski 5641dd5246eSKrzysztof Kozlowski static void bwmon_start(struct icc_bwmon *bwmon) 565b9c2ae6cSKrzysztof Kozlowski { 5661dd5246eSKrzysztof Kozlowski const struct icc_bwmon_data *data = bwmon->data; 567b9c2ae6cSKrzysztof Kozlowski int window; 568b9c2ae6cSKrzysztof Kozlowski 569956deab5SKrzysztof Kozlowski bwmon_clear_counters(bwmon, true); 570b9c2ae6cSKrzysztof Kozlowski 5711dd5246eSKrzysztof Kozlowski window = mult_frac(bwmon->data->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC); 57214af4ce0SKrzysztof Kozlowski /* Maximum sampling window: 0xffffff for v4 and 0xfffff for v5 */ 573ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_SAMPLE_WINDOW], window); 574b9c2ae6cSKrzysztof Kozlowski 575ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], 576b9c2ae6cSKrzysztof Kozlowski data->default_highbw_kbps); 577ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], 578b9c2ae6cSKrzysztof Kozlowski data->default_medbw_kbps); 579ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW], 580b9c2ae6cSKrzysztof Kozlowski data->default_lowbw_kbps); 581b9c2ae6cSKrzysztof Kozlowski 582ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE0], 583ec63dcd3SKrzysztof Kozlowski BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT); 584ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE1], 585ec63dcd3SKrzysztof Kozlowski data->zone1_thres_count); 586ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE2], 587ec63dcd3SKrzysztof Kozlowski BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT); 588ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE3], 589ec63dcd3SKrzysztof Kozlowski data->zone3_thres_count); 590ec63dcd3SKrzysztof Kozlowski 591ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE0], 592ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE0); 593ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE1], 594ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE1); 595ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE2], 596ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE2); 597ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE3], 598ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE3); 599b9c2ae6cSKrzysztof Kozlowski 600b9c2ae6cSKrzysztof Kozlowski bwmon_clear_irq(bwmon); 601b9c2ae6cSKrzysztof Kozlowski bwmon_enable(bwmon, BWMON_IRQ_ENABLE_MASK); 602b9c2ae6cSKrzysztof Kozlowski } 603b9c2ae6cSKrzysztof Kozlowski 604b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr(int irq, void *dev_id) 605b9c2ae6cSKrzysztof Kozlowski { 606b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = dev_id; 607b9c2ae6cSKrzysztof Kozlowski unsigned int status, max; 608b9c2ae6cSKrzysztof Kozlowski int zone; 609b9c2ae6cSKrzysztof Kozlowski 610ec63dcd3SKrzysztof Kozlowski if (regmap_field_read(bwmon->regs[F_IRQ_STATUS], &status)) 611ec63dcd3SKrzysztof Kozlowski return IRQ_NONE; 612ec63dcd3SKrzysztof Kozlowski 613b9c2ae6cSKrzysztof Kozlowski status &= BWMON_IRQ_ENABLE_MASK; 614b9c2ae6cSKrzysztof Kozlowski if (!status) { 615b9c2ae6cSKrzysztof Kozlowski /* 616b9c2ae6cSKrzysztof Kozlowski * Only zone 1 and zone 3 interrupts are enabled but zone 2 617b9c2ae6cSKrzysztof Kozlowski * threshold could be hit and trigger interrupt even if not 618b9c2ae6cSKrzysztof Kozlowski * enabled. 619b9c2ae6cSKrzysztof Kozlowski * Such spurious interrupt might come with valuable max count or 620b9c2ae6cSKrzysztof Kozlowski * not, so solution would be to always check all 621b9c2ae6cSKrzysztof Kozlowski * BWMON_ZONE_MAX() registers to find the highest value. 622b9c2ae6cSKrzysztof Kozlowski * Such case is currently ignored. 623b9c2ae6cSKrzysztof Kozlowski */ 624b9c2ae6cSKrzysztof Kozlowski return IRQ_NONE; 625b9c2ae6cSKrzysztof Kozlowski } 626b9c2ae6cSKrzysztof Kozlowski 627b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon); 628b9c2ae6cSKrzysztof Kozlowski 629ec63dcd3SKrzysztof Kozlowski zone = get_bitmask_order(status) - 1; 630b9c2ae6cSKrzysztof Kozlowski /* 631b9c2ae6cSKrzysztof Kozlowski * Zone max bytes count register returns count units within sampling 632b9c2ae6cSKrzysztof Kozlowski * window. Downstream kernel for BWMONv4 (called BWMON type 2 in 633b9c2ae6cSKrzysztof Kozlowski * downstream) always increments the max bytes count by one. 634b9c2ae6cSKrzysztof Kozlowski */ 635ec63dcd3SKrzysztof Kozlowski if (regmap_field_read(bwmon->regs[F_ZONE0_MAX + zone], &max)) 636ec63dcd3SKrzysztof Kozlowski return IRQ_NONE; 637ec63dcd3SKrzysztof Kozlowski 638ec63dcd3SKrzysztof Kozlowski max += 1; 639650db9faSKrzysztof Kozlowski max *= bwmon->data->count_unit_kb; 6401dd5246eSKrzysztof Kozlowski bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->data->sample_ms); 641b9c2ae6cSKrzysztof Kozlowski 642b9c2ae6cSKrzysztof Kozlowski return IRQ_WAKE_THREAD; 643b9c2ae6cSKrzysztof Kozlowski } 644b9c2ae6cSKrzysztof Kozlowski 645b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr_thread(int irq, void *dev_id) 646b9c2ae6cSKrzysztof Kozlowski { 647b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = dev_id; 648b9c2ae6cSKrzysztof Kozlowski unsigned int irq_enable = 0; 649b9c2ae6cSKrzysztof Kozlowski struct dev_pm_opp *opp, *target_opp; 650b9c2ae6cSKrzysztof Kozlowski unsigned int bw_kbps, up_kbps, down_kbps; 651b9c2ae6cSKrzysztof Kozlowski 652b9c2ae6cSKrzysztof Kozlowski bw_kbps = bwmon->target_kbps; 653b9c2ae6cSKrzysztof Kozlowski 654b9c2ae6cSKrzysztof Kozlowski target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0); 655b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE) 656b9c2ae6cSKrzysztof Kozlowski target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0); 657b9c2ae6cSKrzysztof Kozlowski 658b9c2ae6cSKrzysztof Kozlowski bwmon->target_kbps = bw_kbps; 659b9c2ae6cSKrzysztof Kozlowski 660b9c2ae6cSKrzysztof Kozlowski bw_kbps--; 661b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0); 662b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE) 663b9c2ae6cSKrzysztof Kozlowski down_kbps = bwmon->target_kbps; 664b9c2ae6cSKrzysztof Kozlowski else 665b9c2ae6cSKrzysztof Kozlowski down_kbps = bw_kbps; 666b9c2ae6cSKrzysztof Kozlowski 667b9c2ae6cSKrzysztof Kozlowski up_kbps = bwmon->target_kbps + 1; 668b9c2ae6cSKrzysztof Kozlowski 669b9c2ae6cSKrzysztof Kozlowski if (bwmon->target_kbps >= bwmon->max_bw_kbps) 670ec63dcd3SKrzysztof Kozlowski irq_enable = BIT(1); 671b9c2ae6cSKrzysztof Kozlowski else if (bwmon->target_kbps <= bwmon->min_bw_kbps) 672ec63dcd3SKrzysztof Kozlowski irq_enable = BIT(3); 673b9c2ae6cSKrzysztof Kozlowski else 674b9c2ae6cSKrzysztof Kozlowski irq_enable = BWMON_IRQ_ENABLE_MASK; 675b9c2ae6cSKrzysztof Kozlowski 676ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], 677ec63dcd3SKrzysztof Kozlowski up_kbps); 678ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], 679ec63dcd3SKrzysztof Kozlowski down_kbps); 680956deab5SKrzysztof Kozlowski bwmon_clear_counters(bwmon, false); 681b9c2ae6cSKrzysztof Kozlowski bwmon_clear_irq(bwmon); 682b9c2ae6cSKrzysztof Kozlowski bwmon_enable(bwmon, irq_enable); 683b9c2ae6cSKrzysztof Kozlowski 684b9c2ae6cSKrzysztof Kozlowski if (bwmon->target_kbps == bwmon->current_kbps) 685b9c2ae6cSKrzysztof Kozlowski goto out; 686b9c2ae6cSKrzysztof Kozlowski 687b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_set_opp(bwmon->dev, target_opp); 688b9c2ae6cSKrzysztof Kozlowski bwmon->current_kbps = bwmon->target_kbps; 689b9c2ae6cSKrzysztof Kozlowski 690b9c2ae6cSKrzysztof Kozlowski out: 691b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_put(target_opp); 692b9c2ae6cSKrzysztof Kozlowski if (!IS_ERR(opp)) 693b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_put(opp); 694b9c2ae6cSKrzysztof Kozlowski 695b9c2ae6cSKrzysztof Kozlowski return IRQ_HANDLED; 696b9c2ae6cSKrzysztof Kozlowski } 697b9c2ae6cSKrzysztof Kozlowski 698ec63dcd3SKrzysztof Kozlowski static int bwmon_init_regmap(struct platform_device *pdev, 699ec63dcd3SKrzysztof Kozlowski struct icc_bwmon *bwmon) 700ec63dcd3SKrzysztof Kozlowski { 701ec63dcd3SKrzysztof Kozlowski struct device *dev = &pdev->dev; 702ec63dcd3SKrzysztof Kozlowski void __iomem *base; 703ec63dcd3SKrzysztof Kozlowski struct regmap *map; 704b6e9fb7aSKonrad Dybcio int ret; 705ec63dcd3SKrzysztof Kozlowski 706b6e9fb7aSKonrad Dybcio /* Map the monitor base */ 707ec63dcd3SKrzysztof Kozlowski base = devm_platform_ioremap_resource(pdev, 0); 708ec63dcd3SKrzysztof Kozlowski if (IS_ERR(base)) 709ec63dcd3SKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(base), 710ec63dcd3SKrzysztof Kozlowski "failed to map bwmon registers\n"); 711ec63dcd3SKrzysztof Kozlowski 712ec63dcd3SKrzysztof Kozlowski map = devm_regmap_init_mmio(dev, base, bwmon->data->regmap_cfg); 713ec63dcd3SKrzysztof Kozlowski if (IS_ERR(map)) 714ec63dcd3SKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(map), 715ec63dcd3SKrzysztof Kozlowski "failed to initialize regmap\n"); 716ec63dcd3SKrzysztof Kozlowski 717b6e9fb7aSKonrad Dybcio BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_global_reg_fields) != F_NUM_GLOBAL_FIELDS); 718ec63dcd3SKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_reg_fields) != F_NUM_FIELDS); 719b6e9fb7aSKonrad Dybcio BUILD_BUG_ON(ARRAY_SIZE(sdm845_cpu_bwmon_reg_fields) != F_NUM_FIELDS); 72014af4ce0SKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(sdm845_llcc_bwmon_reg_fields) != F_NUM_FIELDS); 7217eb89c17SJinpeng Cui 722b6e9fb7aSKonrad Dybcio ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->regs, 723ec63dcd3SKrzysztof Kozlowski bwmon->data->regmap_fields, 724ec63dcd3SKrzysztof Kozlowski F_NUM_FIELDS); 725b6e9fb7aSKonrad Dybcio if (ret) 726b6e9fb7aSKonrad Dybcio return ret; 727b6e9fb7aSKonrad Dybcio 728b6e9fb7aSKonrad Dybcio if (bwmon->data->global_regmap_cfg) { 729b6e9fb7aSKonrad Dybcio /* Map the global base, if separate */ 730b6e9fb7aSKonrad Dybcio base = devm_platform_ioremap_resource(pdev, 1); 731b6e9fb7aSKonrad Dybcio if (IS_ERR(base)) 732b6e9fb7aSKonrad Dybcio return dev_err_probe(dev, PTR_ERR(base), 733b6e9fb7aSKonrad Dybcio "failed to map bwmon global registers\n"); 734b6e9fb7aSKonrad Dybcio 735b6e9fb7aSKonrad Dybcio map = devm_regmap_init_mmio(dev, base, bwmon->data->global_regmap_cfg); 736b6e9fb7aSKonrad Dybcio if (IS_ERR(map)) 737b6e9fb7aSKonrad Dybcio return dev_err_probe(dev, PTR_ERR(map), 738b6e9fb7aSKonrad Dybcio "failed to initialize global regmap\n"); 739b6e9fb7aSKonrad Dybcio 740b6e9fb7aSKonrad Dybcio ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->global_regs, 741b6e9fb7aSKonrad Dybcio bwmon->data->global_regmap_fields, 742b6e9fb7aSKonrad Dybcio F_NUM_GLOBAL_FIELDS); 743b6e9fb7aSKonrad Dybcio } 744b6e9fb7aSKonrad Dybcio 745b6e9fb7aSKonrad Dybcio return ret; 746ec63dcd3SKrzysztof Kozlowski } 747ec63dcd3SKrzysztof Kozlowski 748b9c2ae6cSKrzysztof Kozlowski static int bwmon_probe(struct platform_device *pdev) 749b9c2ae6cSKrzysztof Kozlowski { 750b9c2ae6cSKrzysztof Kozlowski struct device *dev = &pdev->dev; 751b9c2ae6cSKrzysztof Kozlowski struct dev_pm_opp *opp; 752b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon; 753b9c2ae6cSKrzysztof Kozlowski int ret; 754b9c2ae6cSKrzysztof Kozlowski 755b9c2ae6cSKrzysztof Kozlowski bwmon = devm_kzalloc(dev, sizeof(*bwmon), GFP_KERNEL); 756b9c2ae6cSKrzysztof Kozlowski if (!bwmon) 757b9c2ae6cSKrzysztof Kozlowski return -ENOMEM; 758b9c2ae6cSKrzysztof Kozlowski 7591dd5246eSKrzysztof Kozlowski bwmon->data = of_device_get_match_data(dev); 760b9c2ae6cSKrzysztof Kozlowski 761ec63dcd3SKrzysztof Kozlowski ret = bwmon_init_regmap(pdev, bwmon); 762ec63dcd3SKrzysztof Kozlowski if (ret) 763ec63dcd3SKrzysztof Kozlowski return ret; 764b9c2ae6cSKrzysztof Kozlowski 765b9c2ae6cSKrzysztof Kozlowski bwmon->irq = platform_get_irq(pdev, 0); 766947bb0d1SYang Li if (bwmon->irq < 0) 767b9c2ae6cSKrzysztof Kozlowski return bwmon->irq; 768b9c2ae6cSKrzysztof Kozlowski 769b9c2ae6cSKrzysztof Kozlowski ret = devm_pm_opp_of_add_table(dev); 770b9c2ae6cSKrzysztof Kozlowski if (ret) 771b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to add OPP table\n"); 772b9c2ae6cSKrzysztof Kozlowski 773b9c2ae6cSKrzysztof Kozlowski bwmon->max_bw_kbps = UINT_MAX; 774b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0); 775b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp)) 776b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to find max peak bandwidth\n"); 777b9c2ae6cSKrzysztof Kozlowski 778b9c2ae6cSKrzysztof Kozlowski bwmon->min_bw_kbps = 0; 779b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0); 780b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp)) 781b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to find min peak bandwidth\n"); 782b9c2ae6cSKrzysztof Kozlowski 783b9c2ae6cSKrzysztof Kozlowski bwmon->dev = dev; 784b9c2ae6cSKrzysztof Kozlowski 785b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon); 786b9c2ae6cSKrzysztof Kozlowski ret = devm_request_threaded_irq(dev, bwmon->irq, bwmon_intr, 787b9c2ae6cSKrzysztof Kozlowski bwmon_intr_thread, 788b9c2ae6cSKrzysztof Kozlowski IRQF_ONESHOT, dev_name(dev), bwmon); 789b9c2ae6cSKrzysztof Kozlowski if (ret) 790b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to request IRQ\n"); 791b9c2ae6cSKrzysztof Kozlowski 792b9c2ae6cSKrzysztof Kozlowski platform_set_drvdata(pdev, bwmon); 7931dd5246eSKrzysztof Kozlowski bwmon_start(bwmon); 794b9c2ae6cSKrzysztof Kozlowski 795b9c2ae6cSKrzysztof Kozlowski return 0; 796b9c2ae6cSKrzysztof Kozlowski } 797b9c2ae6cSKrzysztof Kozlowski 798b9c2ae6cSKrzysztof Kozlowski static int bwmon_remove(struct platform_device *pdev) 799b9c2ae6cSKrzysztof Kozlowski { 800b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = platform_get_drvdata(pdev); 801b9c2ae6cSKrzysztof Kozlowski 802b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon); 803b9c2ae6cSKrzysztof Kozlowski 804b9c2ae6cSKrzysztof Kozlowski return 0; 805b9c2ae6cSKrzysztof Kozlowski } 806b9c2ae6cSKrzysztof Kozlowski 807b9c2ae6cSKrzysztof Kozlowski static const struct icc_bwmon_data msm8998_bwmon_data = { 808b9c2ae6cSKrzysztof Kozlowski .sample_ms = 4, 809*1c8267cdSKonrad Dybcio .count_unit_kb = 1024, 810b9c2ae6cSKrzysztof Kozlowski .default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */ 811b9c2ae6cSKrzysztof Kozlowski .default_medbw_kbps = 512 * 1024, /* 512 MBps */ 812b9c2ae6cSKrzysztof Kozlowski .default_lowbw_kbps = 0, 813b9c2ae6cSKrzysztof Kozlowski .zone1_thres_count = 16, 814b9c2ae6cSKrzysztof Kozlowski .zone3_thres_count = 1, 815e6f34184SKrzysztof Kozlowski .quirks = BWMON_HAS_GLOBAL_IRQ, 816ec63dcd3SKrzysztof Kozlowski .regmap_fields = msm8998_bwmon_reg_fields, 817ec63dcd3SKrzysztof Kozlowski .regmap_cfg = &msm8998_bwmon_regmap_cfg, 818b6e9fb7aSKonrad Dybcio .global_regmap_fields = msm8998_bwmon_global_reg_fields, 819b6e9fb7aSKonrad Dybcio .global_regmap_cfg = &msm8998_bwmon_global_regmap_cfg, 820b6e9fb7aSKonrad Dybcio }; 821b6e9fb7aSKonrad Dybcio 822b6e9fb7aSKonrad Dybcio static const struct icc_bwmon_data sdm845_cpu_bwmon_data = { 823b6e9fb7aSKonrad Dybcio .sample_ms = 4, 824b6e9fb7aSKonrad Dybcio .count_unit_kb = 64, 825b6e9fb7aSKonrad Dybcio .default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */ 826b6e9fb7aSKonrad Dybcio .default_medbw_kbps = 512 * 1024, /* 512 MBps */ 827b6e9fb7aSKonrad Dybcio .default_lowbw_kbps = 0, 828b6e9fb7aSKonrad Dybcio .zone1_thres_count = 16, 829b6e9fb7aSKonrad Dybcio .zone3_thres_count = 1, 830b6e9fb7aSKonrad Dybcio .quirks = BWMON_HAS_GLOBAL_IRQ, 831b6e9fb7aSKonrad Dybcio .regmap_fields = sdm845_cpu_bwmon_reg_fields, 832b6e9fb7aSKonrad Dybcio .regmap_cfg = &sdm845_cpu_bwmon_regmap_cfg, 833b9c2ae6cSKrzysztof Kozlowski }; 834b9c2ae6cSKrzysztof Kozlowski 83514af4ce0SKrzysztof Kozlowski static const struct icc_bwmon_data sdm845_llcc_bwmon_data = { 83614af4ce0SKrzysztof Kozlowski .sample_ms = 4, 83714af4ce0SKrzysztof Kozlowski .count_unit_kb = 1024, 83814af4ce0SKrzysztof Kozlowski .default_highbw_kbps = 800 * 1024, /* 800 MBps */ 83914af4ce0SKrzysztof Kozlowski .default_medbw_kbps = 256 * 1024, /* 256 MBps */ 84014af4ce0SKrzysztof Kozlowski .default_lowbw_kbps = 0, 84114af4ce0SKrzysztof Kozlowski .zone1_thres_count = 16, 84214af4ce0SKrzysztof Kozlowski .zone3_thres_count = 1, 84314af4ce0SKrzysztof Kozlowski .regmap_fields = sdm845_llcc_bwmon_reg_fields, 84414af4ce0SKrzysztof Kozlowski .regmap_cfg = &sdm845_llcc_bwmon_regmap_cfg, 84514af4ce0SKrzysztof Kozlowski }; 84614af4ce0SKrzysztof Kozlowski 8471335fc5bSRajendra Nayak static const struct icc_bwmon_data sc7280_llcc_bwmon_data = { 8481335fc5bSRajendra Nayak .sample_ms = 4, 8491335fc5bSRajendra Nayak .count_unit_kb = 64, 8501335fc5bSRajendra Nayak .default_highbw_kbps = 800 * 1024, /* 800 MBps */ 8511335fc5bSRajendra Nayak .default_medbw_kbps = 256 * 1024, /* 256 MBps */ 8521335fc5bSRajendra Nayak .default_lowbw_kbps = 0, 8531335fc5bSRajendra Nayak .zone1_thres_count = 16, 8541335fc5bSRajendra Nayak .zone3_thres_count = 1, 855cdad59c2SRajendra Nayak .quirks = BWMON_NEEDS_FORCE_CLEAR, 8561335fc5bSRajendra Nayak .regmap_fields = sdm845_llcc_bwmon_reg_fields, 8571335fc5bSRajendra Nayak .regmap_cfg = &sdm845_llcc_bwmon_regmap_cfg, 8581335fc5bSRajendra Nayak }; 8591335fc5bSRajendra Nayak 860b9c2ae6cSKrzysztof Kozlowski static const struct of_device_id bwmon_of_match[] = { 861b6e9fb7aSKonrad Dybcio /* BWMONv4, separate monitor and global register spaces */ 862b6e9fb7aSKonrad Dybcio { .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data }, 863b6e9fb7aSKonrad Dybcio /* BWMONv4, unified register space */ 864b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sdm845-bwmon", .data = &sdm845_cpu_bwmon_data }, 865b6e9fb7aSKonrad Dybcio /* BWMONv5 */ 866b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sdm845-llcc-bwmon", .data = &sdm845_llcc_bwmon_data }, 867b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sc7280-llcc-bwmon", .data = &sc7280_llcc_bwmon_data }, 868b6e9fb7aSKonrad Dybcio 869b6e9fb7aSKonrad Dybcio /* Compatibles kept for legacy reasons */ 870b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sc7280-cpu-bwmon", .data = &sdm845_cpu_bwmon_data }, 871b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sc8280xp-cpu-bwmon", .data = &sdm845_cpu_bwmon_data }, 872b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sm8550-cpu-bwmon", .data = &sdm845_cpu_bwmon_data }, 873b9c2ae6cSKrzysztof Kozlowski {} 874b9c2ae6cSKrzysztof Kozlowski }; 875b9c2ae6cSKrzysztof Kozlowski MODULE_DEVICE_TABLE(of, bwmon_of_match); 876b9c2ae6cSKrzysztof Kozlowski 877b9c2ae6cSKrzysztof Kozlowski static struct platform_driver bwmon_driver = { 878b9c2ae6cSKrzysztof Kozlowski .probe = bwmon_probe, 879b9c2ae6cSKrzysztof Kozlowski .remove = bwmon_remove, 880b9c2ae6cSKrzysztof Kozlowski .driver = { 881b9c2ae6cSKrzysztof Kozlowski .name = "qcom-bwmon", 882b9c2ae6cSKrzysztof Kozlowski .of_match_table = bwmon_of_match, 883b9c2ae6cSKrzysztof Kozlowski }, 884b9c2ae6cSKrzysztof Kozlowski }; 885b9c2ae6cSKrzysztof Kozlowski module_platform_driver(bwmon_driver); 886b9c2ae6cSKrzysztof Kozlowski 887b9c2ae6cSKrzysztof Kozlowski MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>"); 888b9c2ae6cSKrzysztof Kozlowski MODULE_DESCRIPTION("QCOM BWMON driver"); 889b9c2ae6cSKrzysztof Kozlowski MODULE_LICENSE("GPL"); 890