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 37ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_GLOBAL_IRQ_CLEAR 0x008 38ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_GLOBAL_IRQ_ENABLE 0x00c 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 45ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_IRQ_STATUS 0x100 46ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_IRQ_CLEAR 0x108 47b9c2ae6cSKrzysztof Kozlowski 48ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_IRQ_ENABLE 0x10c 49ec63dcd3SKrzysztof Kozlowski #define BWMON_IRQ_ENABLE_MASK (BIT(1) | BIT(3)) 5014af4ce0SKrzysztof Kozlowski #define BWMON_V5_IRQ_STATUS 0x000 5114af4ce0SKrzysztof Kozlowski #define BWMON_V5_IRQ_CLEAR 0x008 5214af4ce0SKrzysztof Kozlowski #define BWMON_V5_IRQ_ENABLE 0x00c 53ec63dcd3SKrzysztof Kozlowski 54ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_ENABLE 0x2a0 5514af4ce0SKrzysztof Kozlowski #define BWMON_V5_ENABLE 0x010 56b9c2ae6cSKrzysztof Kozlowski #define BWMON_ENABLE_ENABLE BIT(0) 57b9c2ae6cSKrzysztof Kozlowski 58ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_CLEAR 0x2a4 5914af4ce0SKrzysztof Kozlowski #define BWMON_V5_CLEAR 0x014 60b9c2ae6cSKrzysztof Kozlowski #define BWMON_CLEAR_CLEAR BIT(0) 61956deab5SKrzysztof Kozlowski #define BWMON_CLEAR_CLEAR_ALL BIT(1) 62b9c2ae6cSKrzysztof Kozlowski 63ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_SAMPLE_WINDOW 0x2a8 6414af4ce0SKrzysztof Kozlowski #define BWMON_V5_SAMPLE_WINDOW 0x020 6514af4ce0SKrzysztof Kozlowski 66ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_HIGH 0x2ac 67ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_MED 0x2b0 68ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_LOW 0x2b4 6914af4ce0SKrzysztof Kozlowski #define BWMON_V5_THRESHOLD_HIGH 0x024 7014af4ce0SKrzysztof Kozlowski #define BWMON_V5_THRESHOLD_MED 0x028 7114af4ce0SKrzysztof Kozlowski #define BWMON_V5_THRESHOLD_LOW 0x02c 72b9c2ae6cSKrzysztof Kozlowski 73ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_ZONE_ACTIONS 0x2b8 7414af4ce0SKrzysztof Kozlowski #define BWMON_V5_ZONE_ACTIONS 0x030 75b9c2ae6cSKrzysztof Kozlowski /* 76b9c2ae6cSKrzysztof Kozlowski * Actions to perform on some zone 'z' when current zone hits the threshold: 77b9c2ae6cSKrzysztof Kozlowski * Increment counter of zone 'z' 78b9c2ae6cSKrzysztof Kozlowski */ 79b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_INCREMENT(z) (0x2 << ((z) * 2)) 80b9c2ae6cSKrzysztof Kozlowski /* Clear counter of zone 'z' */ 81b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_CLEAR(z) (0x1 << ((z) * 2)) 82b9c2ae6cSKrzysztof Kozlowski 83b9c2ae6cSKrzysztof Kozlowski /* Zone 0 threshold hit: Clear zone count */ 84b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE0 (BWMON_ZONE_ACTIONS_CLEAR(0)) 85b9c2ae6cSKrzysztof Kozlowski 86b9c2ae6cSKrzysztof Kozlowski /* Zone 1 threshold hit: Increment zone count & clear lower zones */ 87b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE1 (BWMON_ZONE_ACTIONS_INCREMENT(1) | \ 88b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(0)) 89b9c2ae6cSKrzysztof Kozlowski 90b9c2ae6cSKrzysztof Kozlowski /* Zone 2 threshold hit: Increment zone count & clear lower zones */ 91b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE2 (BWMON_ZONE_ACTIONS_INCREMENT(2) | \ 92b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(1) | \ 93b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(0)) 94b9c2ae6cSKrzysztof Kozlowski 95b9c2ae6cSKrzysztof Kozlowski /* Zone 3 threshold hit: Increment zone count & clear lower zones */ 96b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE3 (BWMON_ZONE_ACTIONS_INCREMENT(3) | \ 97b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(2) | \ 98b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(1) | \ 99b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(0)) 100b9c2ae6cSKrzysztof Kozlowski 101b9c2ae6cSKrzysztof Kozlowski /* 102ec63dcd3SKrzysztof Kozlowski * There is no clear documentation/explanation of BWMON_V4_THRESHOLD_COUNT 103b9c2ae6cSKrzysztof Kozlowski * register. Based on observations, this is number of times one threshold has to 104b9c2ae6cSKrzysztof Kozlowski * be reached, to trigger interrupt in given zone. 105b9c2ae6cSKrzysztof Kozlowski * 106b9c2ae6cSKrzysztof Kozlowski * 0xff are maximum values meant to ignore the zones 0 and 2. 107b9c2ae6cSKrzysztof Kozlowski */ 108ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_THRESHOLD_COUNT 0x2bc 10914af4ce0SKrzysztof Kozlowski #define BWMON_V5_THRESHOLD_COUNT 0x034 110b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT 0xff 111b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT 0xff 112b9c2ae6cSKrzysztof Kozlowski 113ec63dcd3SKrzysztof Kozlowski #define BWMON_V4_ZONE_MAX(zone) (0x2e0 + 4 * (zone)) 11414af4ce0SKrzysztof Kozlowski #define BWMON_V5_ZONE_MAX(zone) (0x044 + 4 * (zone)) 115ec63dcd3SKrzysztof Kozlowski 116e6f34184SKrzysztof Kozlowski /* Quirks for specific BWMON types */ 117e6f34184SKrzysztof Kozlowski #define BWMON_HAS_GLOBAL_IRQ BIT(0) 118*cdad59c2SRajendra Nayak #define BWMON_NEEDS_FORCE_CLEAR BIT(1) 119e6f34184SKrzysztof Kozlowski 120ec63dcd3SKrzysztof Kozlowski enum bwmon_fields { 121ec63dcd3SKrzysztof Kozlowski F_GLOBAL_IRQ_CLEAR, 122ec63dcd3SKrzysztof Kozlowski F_GLOBAL_IRQ_ENABLE, 123ec63dcd3SKrzysztof Kozlowski F_IRQ_STATUS, 124ec63dcd3SKrzysztof Kozlowski F_IRQ_CLEAR, 125ec63dcd3SKrzysztof Kozlowski F_IRQ_ENABLE, 126ec63dcd3SKrzysztof Kozlowski F_ENABLE, 127ec63dcd3SKrzysztof Kozlowski F_CLEAR, 128ec63dcd3SKrzysztof Kozlowski F_SAMPLE_WINDOW, 129ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_HIGH, 130ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_MED, 131ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_LOW, 132ec63dcd3SKrzysztof Kozlowski F_ZONE_ACTIONS_ZONE0, 133ec63dcd3SKrzysztof Kozlowski F_ZONE_ACTIONS_ZONE1, 134ec63dcd3SKrzysztof Kozlowski F_ZONE_ACTIONS_ZONE2, 135ec63dcd3SKrzysztof Kozlowski F_ZONE_ACTIONS_ZONE3, 136ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_COUNT_ZONE0, 137ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_COUNT_ZONE1, 138ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_COUNT_ZONE2, 139ec63dcd3SKrzysztof Kozlowski F_THRESHOLD_COUNT_ZONE3, 140ec63dcd3SKrzysztof Kozlowski F_ZONE0_MAX, 141ec63dcd3SKrzysztof Kozlowski F_ZONE1_MAX, 142ec63dcd3SKrzysztof Kozlowski F_ZONE2_MAX, 143ec63dcd3SKrzysztof Kozlowski F_ZONE3_MAX, 144ec63dcd3SKrzysztof Kozlowski 145ec63dcd3SKrzysztof Kozlowski F_NUM_FIELDS 146ec63dcd3SKrzysztof Kozlowski }; 147b9c2ae6cSKrzysztof Kozlowski 148b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon_data { 149b9c2ae6cSKrzysztof Kozlowski unsigned int sample_ms; 150650db9faSKrzysztof Kozlowski unsigned int count_unit_kb; /* kbytes */ 151b9c2ae6cSKrzysztof Kozlowski unsigned int default_highbw_kbps; 152b9c2ae6cSKrzysztof Kozlowski unsigned int default_medbw_kbps; 153b9c2ae6cSKrzysztof Kozlowski unsigned int default_lowbw_kbps; 154b9c2ae6cSKrzysztof Kozlowski u8 zone1_thres_count; 155b9c2ae6cSKrzysztof Kozlowski u8 zone3_thres_count; 156e6f34184SKrzysztof Kozlowski unsigned int quirks; 157ec63dcd3SKrzysztof Kozlowski 158ec63dcd3SKrzysztof Kozlowski const struct regmap_config *regmap_cfg; 159ec63dcd3SKrzysztof Kozlowski const struct reg_field *regmap_fields; 160b9c2ae6cSKrzysztof Kozlowski }; 161b9c2ae6cSKrzysztof Kozlowski 162b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon { 163b9c2ae6cSKrzysztof Kozlowski struct device *dev; 1641dd5246eSKrzysztof Kozlowski const struct icc_bwmon_data *data; 165b9c2ae6cSKrzysztof Kozlowski int irq; 166b9c2ae6cSKrzysztof Kozlowski 167ec63dcd3SKrzysztof Kozlowski struct regmap *regmap; 168ec63dcd3SKrzysztof Kozlowski struct regmap_field *regs[F_NUM_FIELDS]; 169ec63dcd3SKrzysztof Kozlowski 170b9c2ae6cSKrzysztof Kozlowski unsigned int max_bw_kbps; 171b9c2ae6cSKrzysztof Kozlowski unsigned int min_bw_kbps; 172b9c2ae6cSKrzysztof Kozlowski unsigned int target_kbps; 173b9c2ae6cSKrzysztof Kozlowski unsigned int current_kbps; 174b9c2ae6cSKrzysztof Kozlowski }; 175b9c2ae6cSKrzysztof Kozlowski 176ec63dcd3SKrzysztof Kozlowski /* BWMON v4 */ 177ec63dcd3SKrzysztof Kozlowski static const struct reg_field msm8998_bwmon_reg_fields[] = { 178ec63dcd3SKrzysztof Kozlowski [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0), 179ec63dcd3SKrzysztof Kozlowski [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0), 180ec63dcd3SKrzysztof Kozlowski [F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7), 181ec63dcd3SKrzysztof Kozlowski [F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7), 182ec63dcd3SKrzysztof Kozlowski [F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7), 183ec63dcd3SKrzysztof Kozlowski /* F_ENABLE covers entire register to disable other features */ 184ec63dcd3SKrzysztof Kozlowski [F_ENABLE] = REG_FIELD(BWMON_V4_ENABLE, 0, 31), 185ec63dcd3SKrzysztof Kozlowski [F_CLEAR] = REG_FIELD(BWMON_V4_CLEAR, 0, 1), 186ec63dcd3SKrzysztof Kozlowski [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23), 187ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11), 188ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_MED] = REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11), 189ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11), 190ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7), 191ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15), 192ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23), 193ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31), 194ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7), 195ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15), 196ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23), 197ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31), 198ec63dcd3SKrzysztof Kozlowski [F_ZONE0_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11), 199ec63dcd3SKrzysztof Kozlowski [F_ZONE1_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11), 200ec63dcd3SKrzysztof Kozlowski [F_ZONE2_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11), 201ec63dcd3SKrzysztof Kozlowski [F_ZONE3_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11), 202ec63dcd3SKrzysztof Kozlowski }; 203ec63dcd3SKrzysztof Kozlowski 204ec63dcd3SKrzysztof Kozlowski static const struct regmap_range msm8998_bwmon_reg_noread_ranges[] = { 205ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR), 206ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR), 207ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR), 208ec63dcd3SKrzysztof Kozlowski }; 209ec63dcd3SKrzysztof Kozlowski 210ec63dcd3SKrzysztof Kozlowski static const struct regmap_access_table msm8998_bwmon_reg_read_table = { 211ec63dcd3SKrzysztof Kozlowski .no_ranges = msm8998_bwmon_reg_noread_ranges, 212ec63dcd3SKrzysztof Kozlowski .n_no_ranges = ARRAY_SIZE(msm8998_bwmon_reg_noread_ranges), 213ec63dcd3SKrzysztof Kozlowski }; 214ec63dcd3SKrzysztof Kozlowski 215ec63dcd3SKrzysztof Kozlowski static const struct regmap_range msm8998_bwmon_reg_volatile_ranges[] = { 216ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_IRQ_STATUS, BWMON_V4_IRQ_STATUS), 217ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_ZONE_MAX(0), BWMON_V4_ZONE_MAX(3)), 218ec63dcd3SKrzysztof Kozlowski }; 219ec63dcd3SKrzysztof Kozlowski 220ec63dcd3SKrzysztof Kozlowski static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = { 221ec63dcd3SKrzysztof Kozlowski .yes_ranges = msm8998_bwmon_reg_volatile_ranges, 222ec63dcd3SKrzysztof Kozlowski .n_yes_ranges = ARRAY_SIZE(msm8998_bwmon_reg_volatile_ranges), 223ec63dcd3SKrzysztof Kozlowski }; 224ec63dcd3SKrzysztof Kozlowski 225ec63dcd3SKrzysztof Kozlowski /* 226ec63dcd3SKrzysztof Kozlowski * Fill the cache for non-readable registers only as rest does not really 227ec63dcd3SKrzysztof Kozlowski * matter and can be read from the device. 228ec63dcd3SKrzysztof Kozlowski */ 229ec63dcd3SKrzysztof Kozlowski static const struct reg_default msm8998_bwmon_reg_defaults[] = { 230ec63dcd3SKrzysztof Kozlowski { BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 }, 231ec63dcd3SKrzysztof Kozlowski { BWMON_V4_IRQ_CLEAR, 0x0 }, 232ec63dcd3SKrzysztof Kozlowski { BWMON_V4_CLEAR, 0x0 }, 233ec63dcd3SKrzysztof Kozlowski }; 234ec63dcd3SKrzysztof Kozlowski 235ec63dcd3SKrzysztof Kozlowski static const struct regmap_config msm8998_bwmon_regmap_cfg = { 236ec63dcd3SKrzysztof Kozlowski .reg_bits = 32, 237ec63dcd3SKrzysztof Kozlowski .reg_stride = 4, 238ec63dcd3SKrzysztof Kozlowski .val_bits = 32, 239ec63dcd3SKrzysztof Kozlowski /* 240ec63dcd3SKrzysztof Kozlowski * No concurrent access expected - driver has one interrupt handler, 241ec63dcd3SKrzysztof Kozlowski * regmap is not shared, no driver or user-space API. 242ec63dcd3SKrzysztof Kozlowski */ 243ec63dcd3SKrzysztof Kozlowski .disable_locking = true, 244ec63dcd3SKrzysztof Kozlowski .rd_table = &msm8998_bwmon_reg_read_table, 245ec63dcd3SKrzysztof Kozlowski .volatile_table = &msm8998_bwmon_reg_volatile_table, 246ec63dcd3SKrzysztof Kozlowski .reg_defaults = msm8998_bwmon_reg_defaults, 247ec63dcd3SKrzysztof Kozlowski .num_reg_defaults = ARRAY_SIZE(msm8998_bwmon_reg_defaults), 248ec63dcd3SKrzysztof Kozlowski /* 249ec63dcd3SKrzysztof Kozlowski * Cache is necessary for using regmap fields with non-readable 250ec63dcd3SKrzysztof Kozlowski * registers. 251ec63dcd3SKrzysztof Kozlowski */ 252ec63dcd3SKrzysztof Kozlowski .cache_type = REGCACHE_RBTREE, 253ec63dcd3SKrzysztof Kozlowski }; 254ec63dcd3SKrzysztof Kozlowski 25514af4ce0SKrzysztof Kozlowski /* BWMON v5 */ 25614af4ce0SKrzysztof Kozlowski static const struct reg_field sdm845_llcc_bwmon_reg_fields[] = { 25714af4ce0SKrzysztof Kozlowski [F_GLOBAL_IRQ_CLEAR] = {}, 25814af4ce0SKrzysztof Kozlowski [F_GLOBAL_IRQ_ENABLE] = {}, 25914af4ce0SKrzysztof Kozlowski [F_IRQ_STATUS] = REG_FIELD(BWMON_V5_IRQ_STATUS, 0, 3), 26014af4ce0SKrzysztof Kozlowski [F_IRQ_CLEAR] = REG_FIELD(BWMON_V5_IRQ_CLEAR, 0, 3), 26114af4ce0SKrzysztof Kozlowski [F_IRQ_ENABLE] = REG_FIELD(BWMON_V5_IRQ_ENABLE, 0, 3), 26214af4ce0SKrzysztof Kozlowski /* F_ENABLE covers entire register to disable other features */ 26314af4ce0SKrzysztof Kozlowski [F_ENABLE] = REG_FIELD(BWMON_V5_ENABLE, 0, 31), 26414af4ce0SKrzysztof Kozlowski [F_CLEAR] = REG_FIELD(BWMON_V5_CLEAR, 0, 1), 26514af4ce0SKrzysztof Kozlowski [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V5_SAMPLE_WINDOW, 0, 19), 26614af4ce0SKrzysztof Kozlowski [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V5_THRESHOLD_HIGH, 0, 11), 26714af4ce0SKrzysztof Kozlowski [F_THRESHOLD_MED] = REG_FIELD(BWMON_V5_THRESHOLD_MED, 0, 11), 26814af4ce0SKrzysztof Kozlowski [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V5_THRESHOLD_LOW, 0, 11), 26914af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 0, 7), 27014af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 8, 15), 27114af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 16, 23), 27214af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 24, 31), 27314af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 0, 7), 27414af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 8, 15), 27514af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 16, 23), 27614af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 24, 31), 27714af4ce0SKrzysztof Kozlowski [F_ZONE0_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(0), 0, 11), 27814af4ce0SKrzysztof Kozlowski [F_ZONE1_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(1), 0, 11), 27914af4ce0SKrzysztof Kozlowski [F_ZONE2_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(2), 0, 11), 28014af4ce0SKrzysztof Kozlowski [F_ZONE3_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(3), 0, 11), 28114af4ce0SKrzysztof Kozlowski }; 28214af4ce0SKrzysztof Kozlowski 28314af4ce0SKrzysztof Kozlowski static const struct regmap_range sdm845_llcc_bwmon_reg_noread_ranges[] = { 28414af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_IRQ_CLEAR, BWMON_V5_IRQ_CLEAR), 28514af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_CLEAR, BWMON_V5_CLEAR), 28614af4ce0SKrzysztof Kozlowski }; 28714af4ce0SKrzysztof Kozlowski 28814af4ce0SKrzysztof Kozlowski static const struct regmap_access_table sdm845_llcc_bwmon_reg_read_table = { 28914af4ce0SKrzysztof Kozlowski .no_ranges = sdm845_llcc_bwmon_reg_noread_ranges, 29014af4ce0SKrzysztof Kozlowski .n_no_ranges = ARRAY_SIZE(sdm845_llcc_bwmon_reg_noread_ranges), 29114af4ce0SKrzysztof Kozlowski }; 29214af4ce0SKrzysztof Kozlowski 29314af4ce0SKrzysztof Kozlowski static const struct regmap_range sdm845_llcc_bwmon_reg_volatile_ranges[] = { 29414af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_IRQ_STATUS, BWMON_V5_IRQ_STATUS), 29514af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_ZONE_MAX(0), BWMON_V5_ZONE_MAX(3)), 29614af4ce0SKrzysztof Kozlowski }; 29714af4ce0SKrzysztof Kozlowski 29814af4ce0SKrzysztof Kozlowski static const struct regmap_access_table sdm845_llcc_bwmon_reg_volatile_table = { 29914af4ce0SKrzysztof Kozlowski .yes_ranges = sdm845_llcc_bwmon_reg_volatile_ranges, 30014af4ce0SKrzysztof Kozlowski .n_yes_ranges = ARRAY_SIZE(sdm845_llcc_bwmon_reg_volatile_ranges), 30114af4ce0SKrzysztof Kozlowski }; 30214af4ce0SKrzysztof Kozlowski 30314af4ce0SKrzysztof Kozlowski /* 30414af4ce0SKrzysztof Kozlowski * Fill the cache for non-readable registers only as rest does not really 30514af4ce0SKrzysztof Kozlowski * matter and can be read from the device. 30614af4ce0SKrzysztof Kozlowski */ 30714af4ce0SKrzysztof Kozlowski static const struct reg_default sdm845_llcc_bwmon_reg_defaults[] = { 30814af4ce0SKrzysztof Kozlowski { BWMON_V5_IRQ_CLEAR, 0x0 }, 30914af4ce0SKrzysztof Kozlowski { BWMON_V5_CLEAR, 0x0 }, 31014af4ce0SKrzysztof Kozlowski }; 31114af4ce0SKrzysztof Kozlowski 31214af4ce0SKrzysztof Kozlowski static const struct regmap_config sdm845_llcc_bwmon_regmap_cfg = { 31314af4ce0SKrzysztof Kozlowski .reg_bits = 32, 31414af4ce0SKrzysztof Kozlowski .reg_stride = 4, 31514af4ce0SKrzysztof Kozlowski .val_bits = 32, 31614af4ce0SKrzysztof Kozlowski /* 31714af4ce0SKrzysztof Kozlowski * No concurrent access expected - driver has one interrupt handler, 31814af4ce0SKrzysztof Kozlowski * regmap is not shared, no driver or user-space API. 31914af4ce0SKrzysztof Kozlowski */ 32014af4ce0SKrzysztof Kozlowski .disable_locking = true, 32114af4ce0SKrzysztof Kozlowski .rd_table = &sdm845_llcc_bwmon_reg_read_table, 32214af4ce0SKrzysztof Kozlowski .volatile_table = &sdm845_llcc_bwmon_reg_volatile_table, 32314af4ce0SKrzysztof Kozlowski .reg_defaults = sdm845_llcc_bwmon_reg_defaults, 32414af4ce0SKrzysztof Kozlowski .num_reg_defaults = ARRAY_SIZE(sdm845_llcc_bwmon_reg_defaults), 32514af4ce0SKrzysztof Kozlowski /* 32614af4ce0SKrzysztof Kozlowski * Cache is necessary for using regmap fields with non-readable 32714af4ce0SKrzysztof Kozlowski * registers. 32814af4ce0SKrzysztof Kozlowski */ 32914af4ce0SKrzysztof Kozlowski .cache_type = REGCACHE_RBTREE, 33014af4ce0SKrzysztof Kozlowski }; 33114af4ce0SKrzysztof Kozlowski 332956deab5SKrzysztof Kozlowski static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all) 333b9c2ae6cSKrzysztof Kozlowski { 334956deab5SKrzysztof Kozlowski unsigned int val = BWMON_CLEAR_CLEAR; 335956deab5SKrzysztof Kozlowski 336956deab5SKrzysztof Kozlowski if (clear_all) 337956deab5SKrzysztof Kozlowski val |= BWMON_CLEAR_CLEAR_ALL; 338b9c2ae6cSKrzysztof Kozlowski /* 339b9c2ae6cSKrzysztof Kozlowski * Clear counters. The order and barriers are 340b9c2ae6cSKrzysztof Kozlowski * important. Quoting downstream Qualcomm msm-4.9 tree: 341b9c2ae6cSKrzysztof Kozlowski * 342b9c2ae6cSKrzysztof Kozlowski * The counter clear and IRQ clear bits are not in the same 4KB 343b9c2ae6cSKrzysztof Kozlowski * region. So, we need to make sure the counter clear is completed 344b9c2ae6cSKrzysztof Kozlowski * before we try to clear the IRQ or do any other counter operations. 345b9c2ae6cSKrzysztof Kozlowski */ 346ec63dcd3SKrzysztof Kozlowski regmap_field_force_write(bwmon->regs[F_CLEAR], val); 347*cdad59c2SRajendra Nayak if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR) 348*cdad59c2SRajendra Nayak regmap_field_force_write(bwmon->regs[F_CLEAR], 0); 349b9c2ae6cSKrzysztof Kozlowski } 350b9c2ae6cSKrzysztof Kozlowski 351b9c2ae6cSKrzysztof Kozlowski static void bwmon_clear_irq(struct icc_bwmon *bwmon) 352b9c2ae6cSKrzysztof Kozlowski { 353b9c2ae6cSKrzysztof Kozlowski /* 354b9c2ae6cSKrzysztof Kozlowski * Clear zone and global interrupts. The order and barriers are 355b9c2ae6cSKrzysztof Kozlowski * important. Quoting downstream Qualcomm msm-4.9 tree: 356b9c2ae6cSKrzysztof Kozlowski * 357b9c2ae6cSKrzysztof Kozlowski * Synchronize the local interrupt clear in mon_irq_clear() 358b9c2ae6cSKrzysztof Kozlowski * with the global interrupt clear here. Otherwise, the CPU 359b9c2ae6cSKrzysztof Kozlowski * may reorder the two writes and clear the global interrupt 360b9c2ae6cSKrzysztof Kozlowski * before the local interrupt, causing the global interrupt 361b9c2ae6cSKrzysztof Kozlowski * to be retriggered by the local interrupt still being high. 362b9c2ae6cSKrzysztof Kozlowski * 363b9c2ae6cSKrzysztof Kozlowski * Similarly, because the global registers are in a different 364b9c2ae6cSKrzysztof Kozlowski * region than the local registers, we need to ensure any register 365b9c2ae6cSKrzysztof Kozlowski * writes to enable the monitor after this call are ordered with the 366b9c2ae6cSKrzysztof Kozlowski * clearing here so that local writes don't happen before the 367b9c2ae6cSKrzysztof Kozlowski * interrupt is cleared. 368b9c2ae6cSKrzysztof Kozlowski */ 369ec63dcd3SKrzysztof Kozlowski regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], BWMON_IRQ_ENABLE_MASK); 370*cdad59c2SRajendra Nayak if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR) 371*cdad59c2SRajendra Nayak regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], 0); 372e6f34184SKrzysztof Kozlowski if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) 373ec63dcd3SKrzysztof Kozlowski regmap_field_force_write(bwmon->regs[F_GLOBAL_IRQ_CLEAR], 374ec63dcd3SKrzysztof Kozlowski BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE); 375b9c2ae6cSKrzysztof Kozlowski } 376b9c2ae6cSKrzysztof Kozlowski 377b9c2ae6cSKrzysztof Kozlowski static void bwmon_disable(struct icc_bwmon *bwmon) 378b9c2ae6cSKrzysztof Kozlowski { 379b9c2ae6cSKrzysztof Kozlowski /* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */ 380e6f34184SKrzysztof Kozlowski if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) 381ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE], 0x0); 382ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_IRQ_ENABLE], 0x0); 383b9c2ae6cSKrzysztof Kozlowski 384b9c2ae6cSKrzysztof Kozlowski /* 385b9c2ae6cSKrzysztof Kozlowski * Disable bwmon. Must happen before bwmon_clear_irq() to avoid spurious 386b9c2ae6cSKrzysztof Kozlowski * IRQ. 387b9c2ae6cSKrzysztof Kozlowski */ 388ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ENABLE], 0x0); 389b9c2ae6cSKrzysztof Kozlowski } 390b9c2ae6cSKrzysztof Kozlowski 391b9c2ae6cSKrzysztof Kozlowski static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable) 392b9c2ae6cSKrzysztof Kozlowski { 393b9c2ae6cSKrzysztof Kozlowski /* Enable interrupts */ 394e6f34184SKrzysztof Kozlowski if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ) 395ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_GLOBAL_IRQ_ENABLE], 396ec63dcd3SKrzysztof Kozlowski BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE); 397ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_IRQ_ENABLE], irq_enable); 398b9c2ae6cSKrzysztof Kozlowski 399b9c2ae6cSKrzysztof Kozlowski /* Enable bwmon */ 400ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ENABLE], BWMON_ENABLE_ENABLE); 401b9c2ae6cSKrzysztof Kozlowski } 402b9c2ae6cSKrzysztof Kozlowski 403650db9faSKrzysztof Kozlowski static unsigned int bwmon_kbps_to_count(struct icc_bwmon *bwmon, 404650db9faSKrzysztof Kozlowski unsigned int kbps) 405b9c2ae6cSKrzysztof Kozlowski { 406650db9faSKrzysztof Kozlowski return kbps / bwmon->data->count_unit_kb; 407b9c2ae6cSKrzysztof Kozlowski } 408b9c2ae6cSKrzysztof Kozlowski 409ec63dcd3SKrzysztof Kozlowski static void bwmon_set_threshold(struct icc_bwmon *bwmon, 410ec63dcd3SKrzysztof Kozlowski struct regmap_field *reg, unsigned int kbps) 411b9c2ae6cSKrzysztof Kozlowski { 412b9c2ae6cSKrzysztof Kozlowski unsigned int thres; 413b9c2ae6cSKrzysztof Kozlowski 414650db9faSKrzysztof Kozlowski thres = mult_frac(bwmon_kbps_to_count(bwmon, kbps), 415650db9faSKrzysztof Kozlowski bwmon->data->sample_ms, MSEC_PER_SEC); 416ec63dcd3SKrzysztof Kozlowski regmap_field_write(reg, thres); 417b9c2ae6cSKrzysztof Kozlowski } 418b9c2ae6cSKrzysztof Kozlowski 4191dd5246eSKrzysztof Kozlowski static void bwmon_start(struct icc_bwmon *bwmon) 420b9c2ae6cSKrzysztof Kozlowski { 4211dd5246eSKrzysztof Kozlowski const struct icc_bwmon_data *data = bwmon->data; 422b9c2ae6cSKrzysztof Kozlowski int window; 423b9c2ae6cSKrzysztof Kozlowski 424956deab5SKrzysztof Kozlowski bwmon_clear_counters(bwmon, true); 425b9c2ae6cSKrzysztof Kozlowski 4261dd5246eSKrzysztof Kozlowski window = mult_frac(bwmon->data->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC); 42714af4ce0SKrzysztof Kozlowski /* Maximum sampling window: 0xffffff for v4 and 0xfffff for v5 */ 428ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_SAMPLE_WINDOW], window); 429b9c2ae6cSKrzysztof Kozlowski 430ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], 431b9c2ae6cSKrzysztof Kozlowski data->default_highbw_kbps); 432ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], 433b9c2ae6cSKrzysztof Kozlowski data->default_medbw_kbps); 434ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW], 435b9c2ae6cSKrzysztof Kozlowski data->default_lowbw_kbps); 436b9c2ae6cSKrzysztof Kozlowski 437ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE0], 438ec63dcd3SKrzysztof Kozlowski BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT); 439ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE1], 440ec63dcd3SKrzysztof Kozlowski data->zone1_thres_count); 441ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE2], 442ec63dcd3SKrzysztof Kozlowski BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT); 443ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE3], 444ec63dcd3SKrzysztof Kozlowski data->zone3_thres_count); 445ec63dcd3SKrzysztof Kozlowski 446ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE0], 447ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE0); 448ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE1], 449ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE1); 450ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE2], 451ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE2); 452ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE3], 453ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE3); 454b9c2ae6cSKrzysztof Kozlowski 455b9c2ae6cSKrzysztof Kozlowski bwmon_clear_irq(bwmon); 456b9c2ae6cSKrzysztof Kozlowski bwmon_enable(bwmon, BWMON_IRQ_ENABLE_MASK); 457b9c2ae6cSKrzysztof Kozlowski } 458b9c2ae6cSKrzysztof Kozlowski 459b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr(int irq, void *dev_id) 460b9c2ae6cSKrzysztof Kozlowski { 461b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = dev_id; 462b9c2ae6cSKrzysztof Kozlowski unsigned int status, max; 463b9c2ae6cSKrzysztof Kozlowski int zone; 464b9c2ae6cSKrzysztof Kozlowski 465ec63dcd3SKrzysztof Kozlowski if (regmap_field_read(bwmon->regs[F_IRQ_STATUS], &status)) 466ec63dcd3SKrzysztof Kozlowski return IRQ_NONE; 467ec63dcd3SKrzysztof Kozlowski 468b9c2ae6cSKrzysztof Kozlowski status &= BWMON_IRQ_ENABLE_MASK; 469b9c2ae6cSKrzysztof Kozlowski if (!status) { 470b9c2ae6cSKrzysztof Kozlowski /* 471b9c2ae6cSKrzysztof Kozlowski * Only zone 1 and zone 3 interrupts are enabled but zone 2 472b9c2ae6cSKrzysztof Kozlowski * threshold could be hit and trigger interrupt even if not 473b9c2ae6cSKrzysztof Kozlowski * enabled. 474b9c2ae6cSKrzysztof Kozlowski * Such spurious interrupt might come with valuable max count or 475b9c2ae6cSKrzysztof Kozlowski * not, so solution would be to always check all 476b9c2ae6cSKrzysztof Kozlowski * BWMON_ZONE_MAX() registers to find the highest value. 477b9c2ae6cSKrzysztof Kozlowski * Such case is currently ignored. 478b9c2ae6cSKrzysztof Kozlowski */ 479b9c2ae6cSKrzysztof Kozlowski return IRQ_NONE; 480b9c2ae6cSKrzysztof Kozlowski } 481b9c2ae6cSKrzysztof Kozlowski 482b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon); 483b9c2ae6cSKrzysztof Kozlowski 484ec63dcd3SKrzysztof Kozlowski zone = get_bitmask_order(status) - 1; 485b9c2ae6cSKrzysztof Kozlowski /* 486b9c2ae6cSKrzysztof Kozlowski * Zone max bytes count register returns count units within sampling 487b9c2ae6cSKrzysztof Kozlowski * window. Downstream kernel for BWMONv4 (called BWMON type 2 in 488b9c2ae6cSKrzysztof Kozlowski * downstream) always increments the max bytes count by one. 489b9c2ae6cSKrzysztof Kozlowski */ 490ec63dcd3SKrzysztof Kozlowski if (regmap_field_read(bwmon->regs[F_ZONE0_MAX + zone], &max)) 491ec63dcd3SKrzysztof Kozlowski return IRQ_NONE; 492ec63dcd3SKrzysztof Kozlowski 493ec63dcd3SKrzysztof Kozlowski max += 1; 494650db9faSKrzysztof Kozlowski max *= bwmon->data->count_unit_kb; 4951dd5246eSKrzysztof Kozlowski bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->data->sample_ms); 496b9c2ae6cSKrzysztof Kozlowski 497b9c2ae6cSKrzysztof Kozlowski return IRQ_WAKE_THREAD; 498b9c2ae6cSKrzysztof Kozlowski } 499b9c2ae6cSKrzysztof Kozlowski 500b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr_thread(int irq, void *dev_id) 501b9c2ae6cSKrzysztof Kozlowski { 502b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = dev_id; 503b9c2ae6cSKrzysztof Kozlowski unsigned int irq_enable = 0; 504b9c2ae6cSKrzysztof Kozlowski struct dev_pm_opp *opp, *target_opp; 505b9c2ae6cSKrzysztof Kozlowski unsigned int bw_kbps, up_kbps, down_kbps; 506b9c2ae6cSKrzysztof Kozlowski 507b9c2ae6cSKrzysztof Kozlowski bw_kbps = bwmon->target_kbps; 508b9c2ae6cSKrzysztof Kozlowski 509b9c2ae6cSKrzysztof Kozlowski target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0); 510b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE) 511b9c2ae6cSKrzysztof Kozlowski target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0); 512b9c2ae6cSKrzysztof Kozlowski 513b9c2ae6cSKrzysztof Kozlowski bwmon->target_kbps = bw_kbps; 514b9c2ae6cSKrzysztof Kozlowski 515b9c2ae6cSKrzysztof Kozlowski bw_kbps--; 516b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0); 517b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE) 518b9c2ae6cSKrzysztof Kozlowski down_kbps = bwmon->target_kbps; 519b9c2ae6cSKrzysztof Kozlowski else 520b9c2ae6cSKrzysztof Kozlowski down_kbps = bw_kbps; 521b9c2ae6cSKrzysztof Kozlowski 522b9c2ae6cSKrzysztof Kozlowski up_kbps = bwmon->target_kbps + 1; 523b9c2ae6cSKrzysztof Kozlowski 524b9c2ae6cSKrzysztof Kozlowski if (bwmon->target_kbps >= bwmon->max_bw_kbps) 525ec63dcd3SKrzysztof Kozlowski irq_enable = BIT(1); 526b9c2ae6cSKrzysztof Kozlowski else if (bwmon->target_kbps <= bwmon->min_bw_kbps) 527ec63dcd3SKrzysztof Kozlowski irq_enable = BIT(3); 528b9c2ae6cSKrzysztof Kozlowski else 529b9c2ae6cSKrzysztof Kozlowski irq_enable = BWMON_IRQ_ENABLE_MASK; 530b9c2ae6cSKrzysztof Kozlowski 531ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], 532ec63dcd3SKrzysztof Kozlowski up_kbps); 533ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], 534ec63dcd3SKrzysztof Kozlowski down_kbps); 535956deab5SKrzysztof Kozlowski bwmon_clear_counters(bwmon, false); 536b9c2ae6cSKrzysztof Kozlowski bwmon_clear_irq(bwmon); 537b9c2ae6cSKrzysztof Kozlowski bwmon_enable(bwmon, irq_enable); 538b9c2ae6cSKrzysztof Kozlowski 539b9c2ae6cSKrzysztof Kozlowski if (bwmon->target_kbps == bwmon->current_kbps) 540b9c2ae6cSKrzysztof Kozlowski goto out; 541b9c2ae6cSKrzysztof Kozlowski 542b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_set_opp(bwmon->dev, target_opp); 543b9c2ae6cSKrzysztof Kozlowski bwmon->current_kbps = bwmon->target_kbps; 544b9c2ae6cSKrzysztof Kozlowski 545b9c2ae6cSKrzysztof Kozlowski out: 546b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_put(target_opp); 547b9c2ae6cSKrzysztof Kozlowski if (!IS_ERR(opp)) 548b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_put(opp); 549b9c2ae6cSKrzysztof Kozlowski 550b9c2ae6cSKrzysztof Kozlowski return IRQ_HANDLED; 551b9c2ae6cSKrzysztof Kozlowski } 552b9c2ae6cSKrzysztof Kozlowski 553ec63dcd3SKrzysztof Kozlowski static int bwmon_init_regmap(struct platform_device *pdev, 554ec63dcd3SKrzysztof Kozlowski struct icc_bwmon *bwmon) 555ec63dcd3SKrzysztof Kozlowski { 556ec63dcd3SKrzysztof Kozlowski struct device *dev = &pdev->dev; 557ec63dcd3SKrzysztof Kozlowski void __iomem *base; 558ec63dcd3SKrzysztof Kozlowski struct regmap *map; 559ec63dcd3SKrzysztof Kozlowski 560ec63dcd3SKrzysztof Kozlowski base = devm_platform_ioremap_resource(pdev, 0); 561ec63dcd3SKrzysztof Kozlowski if (IS_ERR(base)) 562ec63dcd3SKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(base), 563ec63dcd3SKrzysztof Kozlowski "failed to map bwmon registers\n"); 564ec63dcd3SKrzysztof Kozlowski 565ec63dcd3SKrzysztof Kozlowski map = devm_regmap_init_mmio(dev, base, bwmon->data->regmap_cfg); 566ec63dcd3SKrzysztof Kozlowski if (IS_ERR(map)) 567ec63dcd3SKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(map), 568ec63dcd3SKrzysztof Kozlowski "failed to initialize regmap\n"); 569ec63dcd3SKrzysztof Kozlowski 570ec63dcd3SKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_reg_fields) != F_NUM_FIELDS); 57114af4ce0SKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(sdm845_llcc_bwmon_reg_fields) != F_NUM_FIELDS); 5727eb89c17SJinpeng Cui 5737eb89c17SJinpeng Cui return devm_regmap_field_bulk_alloc(dev, map, bwmon->regs, 574ec63dcd3SKrzysztof Kozlowski bwmon->data->regmap_fields, 575ec63dcd3SKrzysztof Kozlowski F_NUM_FIELDS); 576ec63dcd3SKrzysztof Kozlowski } 577ec63dcd3SKrzysztof Kozlowski 578b9c2ae6cSKrzysztof Kozlowski static int bwmon_probe(struct platform_device *pdev) 579b9c2ae6cSKrzysztof Kozlowski { 580b9c2ae6cSKrzysztof Kozlowski struct device *dev = &pdev->dev; 581b9c2ae6cSKrzysztof Kozlowski struct dev_pm_opp *opp; 582b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon; 583b9c2ae6cSKrzysztof Kozlowski int ret; 584b9c2ae6cSKrzysztof Kozlowski 585b9c2ae6cSKrzysztof Kozlowski bwmon = devm_kzalloc(dev, sizeof(*bwmon), GFP_KERNEL); 586b9c2ae6cSKrzysztof Kozlowski if (!bwmon) 587b9c2ae6cSKrzysztof Kozlowski return -ENOMEM; 588b9c2ae6cSKrzysztof Kozlowski 5891dd5246eSKrzysztof Kozlowski bwmon->data = of_device_get_match_data(dev); 590b9c2ae6cSKrzysztof Kozlowski 591ec63dcd3SKrzysztof Kozlowski ret = bwmon_init_regmap(pdev, bwmon); 592ec63dcd3SKrzysztof Kozlowski if (ret) 593ec63dcd3SKrzysztof Kozlowski return ret; 594b9c2ae6cSKrzysztof Kozlowski 595b9c2ae6cSKrzysztof Kozlowski bwmon->irq = platform_get_irq(pdev, 0); 596947bb0d1SYang Li if (bwmon->irq < 0) 597b9c2ae6cSKrzysztof Kozlowski return bwmon->irq; 598b9c2ae6cSKrzysztof Kozlowski 599b9c2ae6cSKrzysztof Kozlowski ret = devm_pm_opp_of_add_table(dev); 600b9c2ae6cSKrzysztof Kozlowski if (ret) 601b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to add OPP table\n"); 602b9c2ae6cSKrzysztof Kozlowski 603b9c2ae6cSKrzysztof Kozlowski bwmon->max_bw_kbps = UINT_MAX; 604b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0); 605b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp)) 606b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to find max peak bandwidth\n"); 607b9c2ae6cSKrzysztof Kozlowski 608b9c2ae6cSKrzysztof Kozlowski bwmon->min_bw_kbps = 0; 609b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0); 610b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp)) 611b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to find min peak bandwidth\n"); 612b9c2ae6cSKrzysztof Kozlowski 613b9c2ae6cSKrzysztof Kozlowski bwmon->dev = dev; 614b9c2ae6cSKrzysztof Kozlowski 615b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon); 616b9c2ae6cSKrzysztof Kozlowski ret = devm_request_threaded_irq(dev, bwmon->irq, bwmon_intr, 617b9c2ae6cSKrzysztof Kozlowski bwmon_intr_thread, 618b9c2ae6cSKrzysztof Kozlowski IRQF_ONESHOT, dev_name(dev), bwmon); 619b9c2ae6cSKrzysztof Kozlowski if (ret) 620b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to request IRQ\n"); 621b9c2ae6cSKrzysztof Kozlowski 622b9c2ae6cSKrzysztof Kozlowski platform_set_drvdata(pdev, bwmon); 6231dd5246eSKrzysztof Kozlowski bwmon_start(bwmon); 624b9c2ae6cSKrzysztof Kozlowski 625b9c2ae6cSKrzysztof Kozlowski return 0; 626b9c2ae6cSKrzysztof Kozlowski } 627b9c2ae6cSKrzysztof Kozlowski 628b9c2ae6cSKrzysztof Kozlowski static int bwmon_remove(struct platform_device *pdev) 629b9c2ae6cSKrzysztof Kozlowski { 630b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = platform_get_drvdata(pdev); 631b9c2ae6cSKrzysztof Kozlowski 632b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon); 633b9c2ae6cSKrzysztof Kozlowski 634b9c2ae6cSKrzysztof Kozlowski return 0; 635b9c2ae6cSKrzysztof Kozlowski } 636b9c2ae6cSKrzysztof Kozlowski 637b9c2ae6cSKrzysztof Kozlowski static const struct icc_bwmon_data msm8998_bwmon_data = { 638b9c2ae6cSKrzysztof Kozlowski .sample_ms = 4, 639650db9faSKrzysztof Kozlowski .count_unit_kb = 64, 640b9c2ae6cSKrzysztof Kozlowski .default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */ 641b9c2ae6cSKrzysztof Kozlowski .default_medbw_kbps = 512 * 1024, /* 512 MBps */ 642b9c2ae6cSKrzysztof Kozlowski .default_lowbw_kbps = 0, 643b9c2ae6cSKrzysztof Kozlowski .zone1_thres_count = 16, 644b9c2ae6cSKrzysztof Kozlowski .zone3_thres_count = 1, 645e6f34184SKrzysztof Kozlowski .quirks = BWMON_HAS_GLOBAL_IRQ, 646ec63dcd3SKrzysztof Kozlowski .regmap_fields = msm8998_bwmon_reg_fields, 647ec63dcd3SKrzysztof Kozlowski .regmap_cfg = &msm8998_bwmon_regmap_cfg, 648b9c2ae6cSKrzysztof Kozlowski }; 649b9c2ae6cSKrzysztof Kozlowski 65014af4ce0SKrzysztof Kozlowski static const struct icc_bwmon_data sdm845_llcc_bwmon_data = { 65114af4ce0SKrzysztof Kozlowski .sample_ms = 4, 65214af4ce0SKrzysztof Kozlowski .count_unit_kb = 1024, 65314af4ce0SKrzysztof Kozlowski .default_highbw_kbps = 800 * 1024, /* 800 MBps */ 65414af4ce0SKrzysztof Kozlowski .default_medbw_kbps = 256 * 1024, /* 256 MBps */ 65514af4ce0SKrzysztof Kozlowski .default_lowbw_kbps = 0, 65614af4ce0SKrzysztof Kozlowski .zone1_thres_count = 16, 65714af4ce0SKrzysztof Kozlowski .zone3_thres_count = 1, 65814af4ce0SKrzysztof Kozlowski .regmap_fields = sdm845_llcc_bwmon_reg_fields, 65914af4ce0SKrzysztof Kozlowski .regmap_cfg = &sdm845_llcc_bwmon_regmap_cfg, 66014af4ce0SKrzysztof Kozlowski }; 66114af4ce0SKrzysztof Kozlowski 6621335fc5bSRajendra Nayak static const struct icc_bwmon_data sc7280_llcc_bwmon_data = { 6631335fc5bSRajendra Nayak .sample_ms = 4, 6641335fc5bSRajendra Nayak .count_unit_kb = 64, 6651335fc5bSRajendra Nayak .default_highbw_kbps = 800 * 1024, /* 800 MBps */ 6661335fc5bSRajendra Nayak .default_medbw_kbps = 256 * 1024, /* 256 MBps */ 6671335fc5bSRajendra Nayak .default_lowbw_kbps = 0, 6681335fc5bSRajendra Nayak .zone1_thres_count = 16, 6691335fc5bSRajendra Nayak .zone3_thres_count = 1, 670*cdad59c2SRajendra Nayak .quirks = BWMON_NEEDS_FORCE_CLEAR, 6711335fc5bSRajendra Nayak .regmap_fields = sdm845_llcc_bwmon_reg_fields, 6721335fc5bSRajendra Nayak .regmap_cfg = &sdm845_llcc_bwmon_regmap_cfg, 6731335fc5bSRajendra Nayak }; 6741335fc5bSRajendra Nayak 675b9c2ae6cSKrzysztof Kozlowski static const struct of_device_id bwmon_of_match[] = { 67614af4ce0SKrzysztof Kozlowski { 67714af4ce0SKrzysztof Kozlowski .compatible = "qcom,msm8998-bwmon", 67814af4ce0SKrzysztof Kozlowski .data = &msm8998_bwmon_data 67914af4ce0SKrzysztof Kozlowski }, { 68014af4ce0SKrzysztof Kozlowski .compatible = "qcom,sdm845-llcc-bwmon", 68114af4ce0SKrzysztof Kozlowski .data = &sdm845_llcc_bwmon_data 6821335fc5bSRajendra Nayak }, { 6831335fc5bSRajendra Nayak .compatible = "qcom,sc7280-llcc-bwmon", 6841335fc5bSRajendra Nayak .data = &sc7280_llcc_bwmon_data 68514af4ce0SKrzysztof Kozlowski }, 686b9c2ae6cSKrzysztof Kozlowski {} 687b9c2ae6cSKrzysztof Kozlowski }; 688b9c2ae6cSKrzysztof Kozlowski MODULE_DEVICE_TABLE(of, bwmon_of_match); 689b9c2ae6cSKrzysztof Kozlowski 690b9c2ae6cSKrzysztof Kozlowski static struct platform_driver bwmon_driver = { 691b9c2ae6cSKrzysztof Kozlowski .probe = bwmon_probe, 692b9c2ae6cSKrzysztof Kozlowski .remove = bwmon_remove, 693b9c2ae6cSKrzysztof Kozlowski .driver = { 694b9c2ae6cSKrzysztof Kozlowski .name = "qcom-bwmon", 695b9c2ae6cSKrzysztof Kozlowski .of_match_table = bwmon_of_match, 696b9c2ae6cSKrzysztof Kozlowski }, 697b9c2ae6cSKrzysztof Kozlowski }; 698b9c2ae6cSKrzysztof Kozlowski module_platform_driver(bwmon_driver); 699b9c2ae6cSKrzysztof Kozlowski 700b9c2ae6cSKrzysztof Kozlowski MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>"); 701b9c2ae6cSKrzysztof Kozlowski MODULE_DESCRIPTION("QCOM BWMON driver"); 702b9c2ae6cSKrzysztof Kozlowski MODULE_LICENSE("GPL"); 703