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 */ 8b9c2ae6cSKrzysztof Kozlowski #include <linux/interconnect.h> 9b9c2ae6cSKrzysztof Kozlowski #include <linux/interrupt.h> 10b9c2ae6cSKrzysztof Kozlowski #include <linux/io.h> 11b9c2ae6cSKrzysztof Kozlowski #include <linux/kernel.h> 12b9c2ae6cSKrzysztof Kozlowski #include <linux/module.h> 13b9c2ae6cSKrzysztof Kozlowski #include <linux/of_device.h> 14b9c2ae6cSKrzysztof Kozlowski #include <linux/platform_device.h> 15b9c2ae6cSKrzysztof Kozlowski #include <linux/pm_opp.h> 16b9c2ae6cSKrzysztof Kozlowski #include <linux/sizes.h> 17b9c2ae6cSKrzysztof Kozlowski 18b9c2ae6cSKrzysztof Kozlowski /* 19b9c2ae6cSKrzysztof Kozlowski * The BWMON samples data throughput within 'sample_ms' time. With three 20b9c2ae6cSKrzysztof Kozlowski * configurable thresholds (Low, Medium and High) gives four windows (called 21b9c2ae6cSKrzysztof Kozlowski * zones) of current bandwidth: 22b9c2ae6cSKrzysztof Kozlowski * 23b9c2ae6cSKrzysztof Kozlowski * Zone 0: byte count < THRES_LO 24b9c2ae6cSKrzysztof Kozlowski * Zone 1: THRES_LO < byte count < THRES_MED 25b9c2ae6cSKrzysztof Kozlowski * Zone 2: THRES_MED < byte count < THRES_HIGH 26b9c2ae6cSKrzysztof Kozlowski * Zone 3: THRES_HIGH < byte count 27b9c2ae6cSKrzysztof Kozlowski * 28b9c2ae6cSKrzysztof Kozlowski * Zones 0 and 2 are not used by this driver. 29b9c2ae6cSKrzysztof Kozlowski */ 30b9c2ae6cSKrzysztof Kozlowski 31b9c2ae6cSKrzysztof Kozlowski /* Internal sampling clock frequency */ 32b9c2ae6cSKrzysztof Kozlowski #define HW_TIMER_HZ 19200000 33b9c2ae6cSKrzysztof Kozlowski 34b9c2ae6cSKrzysztof Kozlowski #define BWMON_GLOBAL_IRQ_STATUS 0x0 35b9c2ae6cSKrzysztof Kozlowski #define BWMON_GLOBAL_IRQ_CLEAR 0x8 36b9c2ae6cSKrzysztof Kozlowski #define BWMON_GLOBAL_IRQ_ENABLE 0xc 37b9c2ae6cSKrzysztof Kozlowski #define BWMON_GLOBAL_IRQ_ENABLE_ENABLE BIT(0) 38b9c2ae6cSKrzysztof Kozlowski 39b9c2ae6cSKrzysztof Kozlowski #define BWMON_IRQ_STATUS 0x100 40b9c2ae6cSKrzysztof Kozlowski #define BWMON_IRQ_STATUS_ZONE_SHIFT 4 41b9c2ae6cSKrzysztof Kozlowski #define BWMON_IRQ_CLEAR 0x108 42b9c2ae6cSKrzysztof Kozlowski #define BWMON_IRQ_ENABLE 0x10c 43b9c2ae6cSKrzysztof Kozlowski #define BWMON_IRQ_ENABLE_ZONE1_SHIFT 5 44b9c2ae6cSKrzysztof Kozlowski #define BWMON_IRQ_ENABLE_ZONE2_SHIFT 6 45b9c2ae6cSKrzysztof Kozlowski #define BWMON_IRQ_ENABLE_ZONE3_SHIFT 7 46b9c2ae6cSKrzysztof Kozlowski #define BWMON_IRQ_ENABLE_MASK (BIT(BWMON_IRQ_ENABLE_ZONE1_SHIFT) | \ 47b9c2ae6cSKrzysztof Kozlowski BIT(BWMON_IRQ_ENABLE_ZONE3_SHIFT)) 48b9c2ae6cSKrzysztof Kozlowski 49b9c2ae6cSKrzysztof Kozlowski #define BWMON_ENABLE 0x2a0 50b9c2ae6cSKrzysztof Kozlowski #define BWMON_ENABLE_ENABLE BIT(0) 51b9c2ae6cSKrzysztof Kozlowski 52b9c2ae6cSKrzysztof Kozlowski #define BWMON_CLEAR 0x2a4 53b9c2ae6cSKrzysztof Kozlowski #define BWMON_CLEAR_CLEAR BIT(0) 54b9c2ae6cSKrzysztof Kozlowski 55b9c2ae6cSKrzysztof Kozlowski #define BWMON_SAMPLE_WINDOW 0x2a8 56b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_HIGH 0x2ac 57b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_MED 0x2b0 58b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_LOW 0x2b4 59b9c2ae6cSKrzysztof Kozlowski 60b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS 0x2b8 61b9c2ae6cSKrzysztof Kozlowski /* 62b9c2ae6cSKrzysztof Kozlowski * Actions to perform on some zone 'z' when current zone hits the threshold: 63b9c2ae6cSKrzysztof Kozlowski * Increment counter of zone 'z' 64b9c2ae6cSKrzysztof Kozlowski */ 65b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_INCREMENT(z) (0x2 << ((z) * 2)) 66b9c2ae6cSKrzysztof Kozlowski /* Clear counter of zone 'z' */ 67b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_CLEAR(z) (0x1 << ((z) * 2)) 68b9c2ae6cSKrzysztof Kozlowski 69b9c2ae6cSKrzysztof Kozlowski /* Zone 0 threshold hit: Clear zone count */ 70b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE0 (BWMON_ZONE_ACTIONS_CLEAR(0)) 71b9c2ae6cSKrzysztof Kozlowski 72b9c2ae6cSKrzysztof Kozlowski /* Zone 1 threshold hit: Increment zone count & clear lower zones */ 73b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE1 (BWMON_ZONE_ACTIONS_INCREMENT(1) | \ 74b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(0)) 75b9c2ae6cSKrzysztof Kozlowski 76b9c2ae6cSKrzysztof Kozlowski /* Zone 2 threshold hit: Increment zone count & clear lower zones */ 77b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE2 (BWMON_ZONE_ACTIONS_INCREMENT(2) | \ 78b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(1) | \ 79b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(0)) 80b9c2ae6cSKrzysztof Kozlowski 81b9c2ae6cSKrzysztof Kozlowski /* Zone 3 threshold hit: Increment zone count & clear lower zones */ 82b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_ZONE3 (BWMON_ZONE_ACTIONS_INCREMENT(3) | \ 83b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(2) | \ 84b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(1) | \ 85b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_CLEAR(0)) 86b9c2ae6cSKrzysztof Kozlowski /* Value for BWMON_ZONE_ACTIONS */ 87b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_ACTIONS_DEFAULT (BWMON_ZONE_ACTIONS_ZONE0 | \ 88b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE1 << 8 | \ 89b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE2 << 16 | \ 90b9c2ae6cSKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE3 << 24) 91b9c2ae6cSKrzysztof Kozlowski 92b9c2ae6cSKrzysztof Kozlowski /* 93b9c2ae6cSKrzysztof Kozlowski * There is no clear documentation/explanation of BWMON_THRESHOLD_COUNT 94b9c2ae6cSKrzysztof Kozlowski * register. Based on observations, this is number of times one threshold has to 95b9c2ae6cSKrzysztof Kozlowski * be reached, to trigger interrupt in given zone. 96b9c2ae6cSKrzysztof Kozlowski * 97b9c2ae6cSKrzysztof Kozlowski * 0xff are maximum values meant to ignore the zones 0 and 2. 98b9c2ae6cSKrzysztof Kozlowski */ 99b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT 0x2bc 100b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE1_SHIFT 8 101b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE2_SHIFT 16 102b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE3_SHIFT 24 103b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT 0xff 104b9c2ae6cSKrzysztof Kozlowski #define BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT 0xff 105b9c2ae6cSKrzysztof Kozlowski 106b9c2ae6cSKrzysztof Kozlowski /* BWMONv4 count registers use count unit of 64 kB */ 107b9c2ae6cSKrzysztof Kozlowski #define BWMON_COUNT_UNIT_KB 64 108b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_COUNT 0x2d8 109b9c2ae6cSKrzysztof Kozlowski #define BWMON_ZONE_MAX(zone) (0x2e0 + 4 * (zone)) 110b9c2ae6cSKrzysztof Kozlowski 111b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon_data { 112b9c2ae6cSKrzysztof Kozlowski unsigned int sample_ms; 113b9c2ae6cSKrzysztof Kozlowski unsigned int default_highbw_kbps; 114b9c2ae6cSKrzysztof Kozlowski unsigned int default_medbw_kbps; 115b9c2ae6cSKrzysztof Kozlowski unsigned int default_lowbw_kbps; 116b9c2ae6cSKrzysztof Kozlowski u8 zone1_thres_count; 117b9c2ae6cSKrzysztof Kozlowski u8 zone3_thres_count; 118b9c2ae6cSKrzysztof Kozlowski }; 119b9c2ae6cSKrzysztof Kozlowski 120b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon { 121b9c2ae6cSKrzysztof Kozlowski struct device *dev; 122b9c2ae6cSKrzysztof Kozlowski void __iomem *base; 123b9c2ae6cSKrzysztof Kozlowski int irq; 124b9c2ae6cSKrzysztof Kozlowski 125b9c2ae6cSKrzysztof Kozlowski unsigned int default_lowbw_kbps; 126b9c2ae6cSKrzysztof Kozlowski unsigned int sample_ms; 127b9c2ae6cSKrzysztof Kozlowski unsigned int max_bw_kbps; 128b9c2ae6cSKrzysztof Kozlowski unsigned int min_bw_kbps; 129b9c2ae6cSKrzysztof Kozlowski unsigned int target_kbps; 130b9c2ae6cSKrzysztof Kozlowski unsigned int current_kbps; 131b9c2ae6cSKrzysztof Kozlowski }; 132b9c2ae6cSKrzysztof Kozlowski 133b9c2ae6cSKrzysztof Kozlowski static void bwmon_clear_counters(struct icc_bwmon *bwmon) 134b9c2ae6cSKrzysztof Kozlowski { 135b9c2ae6cSKrzysztof Kozlowski /* 136b9c2ae6cSKrzysztof Kozlowski * Clear counters. The order and barriers are 137b9c2ae6cSKrzysztof Kozlowski * important. Quoting downstream Qualcomm msm-4.9 tree: 138b9c2ae6cSKrzysztof Kozlowski * 139b9c2ae6cSKrzysztof Kozlowski * The counter clear and IRQ clear bits are not in the same 4KB 140b9c2ae6cSKrzysztof Kozlowski * region. So, we need to make sure the counter clear is completed 141b9c2ae6cSKrzysztof Kozlowski * before we try to clear the IRQ or do any other counter operations. 142b9c2ae6cSKrzysztof Kozlowski */ 143b9c2ae6cSKrzysztof Kozlowski writel(BWMON_CLEAR_CLEAR, bwmon->base + BWMON_CLEAR); 144b9c2ae6cSKrzysztof Kozlowski } 145b9c2ae6cSKrzysztof Kozlowski 146b9c2ae6cSKrzysztof Kozlowski static void bwmon_clear_irq(struct icc_bwmon *bwmon) 147b9c2ae6cSKrzysztof Kozlowski { 148b9c2ae6cSKrzysztof Kozlowski /* 149b9c2ae6cSKrzysztof Kozlowski * Clear zone and global interrupts. The order and barriers are 150b9c2ae6cSKrzysztof Kozlowski * important. Quoting downstream Qualcomm msm-4.9 tree: 151b9c2ae6cSKrzysztof Kozlowski * 152b9c2ae6cSKrzysztof Kozlowski * Synchronize the local interrupt clear in mon_irq_clear() 153b9c2ae6cSKrzysztof Kozlowski * with the global interrupt clear here. Otherwise, the CPU 154b9c2ae6cSKrzysztof Kozlowski * may reorder the two writes and clear the global interrupt 155b9c2ae6cSKrzysztof Kozlowski * before the local interrupt, causing the global interrupt 156b9c2ae6cSKrzysztof Kozlowski * to be retriggered by the local interrupt still being high. 157b9c2ae6cSKrzysztof Kozlowski * 158b9c2ae6cSKrzysztof Kozlowski * Similarly, because the global registers are in a different 159b9c2ae6cSKrzysztof Kozlowski * region than the local registers, we need to ensure any register 160b9c2ae6cSKrzysztof Kozlowski * writes to enable the monitor after this call are ordered with the 161b9c2ae6cSKrzysztof Kozlowski * clearing here so that local writes don't happen before the 162b9c2ae6cSKrzysztof Kozlowski * interrupt is cleared. 163b9c2ae6cSKrzysztof Kozlowski */ 164b9c2ae6cSKrzysztof Kozlowski writel(BWMON_IRQ_ENABLE_MASK, bwmon->base + BWMON_IRQ_CLEAR); 165*6356c7bbSKrzysztof Kozlowski writel(BWMON_GLOBAL_IRQ_ENABLE_ENABLE, 166*6356c7bbSKrzysztof Kozlowski bwmon->base + BWMON_GLOBAL_IRQ_CLEAR); 167b9c2ae6cSKrzysztof Kozlowski } 168b9c2ae6cSKrzysztof Kozlowski 169b9c2ae6cSKrzysztof Kozlowski static void bwmon_disable(struct icc_bwmon *bwmon) 170b9c2ae6cSKrzysztof Kozlowski { 171b9c2ae6cSKrzysztof Kozlowski /* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */ 172b9c2ae6cSKrzysztof Kozlowski writel(0x0, bwmon->base + BWMON_GLOBAL_IRQ_ENABLE); 173b9c2ae6cSKrzysztof Kozlowski writel(0x0, bwmon->base + BWMON_IRQ_ENABLE); 174b9c2ae6cSKrzysztof Kozlowski 175b9c2ae6cSKrzysztof Kozlowski /* 176b9c2ae6cSKrzysztof Kozlowski * Disable bwmon. Must happen before bwmon_clear_irq() to avoid spurious 177b9c2ae6cSKrzysztof Kozlowski * IRQ. 178b9c2ae6cSKrzysztof Kozlowski */ 179b9c2ae6cSKrzysztof Kozlowski writel(0x0, bwmon->base + BWMON_ENABLE); 180b9c2ae6cSKrzysztof Kozlowski } 181b9c2ae6cSKrzysztof Kozlowski 182b9c2ae6cSKrzysztof Kozlowski static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable) 183b9c2ae6cSKrzysztof Kozlowski { 184b9c2ae6cSKrzysztof Kozlowski /* Enable interrupts */ 185b9c2ae6cSKrzysztof Kozlowski writel(BWMON_GLOBAL_IRQ_ENABLE_ENABLE, 186b9c2ae6cSKrzysztof Kozlowski bwmon->base + BWMON_GLOBAL_IRQ_ENABLE); 187b9c2ae6cSKrzysztof Kozlowski writel(irq_enable, bwmon->base + BWMON_IRQ_ENABLE); 188b9c2ae6cSKrzysztof Kozlowski 189b9c2ae6cSKrzysztof Kozlowski /* Enable bwmon */ 190b9c2ae6cSKrzysztof Kozlowski writel(BWMON_ENABLE_ENABLE, bwmon->base + BWMON_ENABLE); 191b9c2ae6cSKrzysztof Kozlowski } 192b9c2ae6cSKrzysztof Kozlowski 193b9c2ae6cSKrzysztof Kozlowski static unsigned int bwmon_kbps_to_count(unsigned int kbps) 194b9c2ae6cSKrzysztof Kozlowski { 195b9c2ae6cSKrzysztof Kozlowski return kbps / BWMON_COUNT_UNIT_KB; 196b9c2ae6cSKrzysztof Kozlowski } 197b9c2ae6cSKrzysztof Kozlowski 198b9c2ae6cSKrzysztof Kozlowski static void bwmon_set_threshold(struct icc_bwmon *bwmon, unsigned int reg, 199b9c2ae6cSKrzysztof Kozlowski unsigned int kbps) 200b9c2ae6cSKrzysztof Kozlowski { 201b9c2ae6cSKrzysztof Kozlowski unsigned int thres; 202b9c2ae6cSKrzysztof Kozlowski 203b9c2ae6cSKrzysztof Kozlowski thres = mult_frac(bwmon_kbps_to_count(kbps), bwmon->sample_ms, 204b9c2ae6cSKrzysztof Kozlowski MSEC_PER_SEC); 205b9c2ae6cSKrzysztof Kozlowski writel_relaxed(thres, bwmon->base + reg); 206b9c2ae6cSKrzysztof Kozlowski } 207b9c2ae6cSKrzysztof Kozlowski 208b9c2ae6cSKrzysztof Kozlowski static void bwmon_start(struct icc_bwmon *bwmon, 209b9c2ae6cSKrzysztof Kozlowski const struct icc_bwmon_data *data) 210b9c2ae6cSKrzysztof Kozlowski { 211b9c2ae6cSKrzysztof Kozlowski unsigned int thres_count; 212b9c2ae6cSKrzysztof Kozlowski int window; 213b9c2ae6cSKrzysztof Kozlowski 214b9c2ae6cSKrzysztof Kozlowski bwmon_clear_counters(bwmon); 215b9c2ae6cSKrzysztof Kozlowski 216b9c2ae6cSKrzysztof Kozlowski window = mult_frac(bwmon->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC); 217b9c2ae6cSKrzysztof Kozlowski /* Maximum sampling window: 0xfffff */ 218b9c2ae6cSKrzysztof Kozlowski writel_relaxed(window, bwmon->base + BWMON_SAMPLE_WINDOW); 219b9c2ae6cSKrzysztof Kozlowski 220b9c2ae6cSKrzysztof Kozlowski bwmon_set_threshold(bwmon, BWMON_THRESHOLD_HIGH, 221b9c2ae6cSKrzysztof Kozlowski data->default_highbw_kbps); 222b9c2ae6cSKrzysztof Kozlowski bwmon_set_threshold(bwmon, BWMON_THRESHOLD_MED, 223b9c2ae6cSKrzysztof Kozlowski data->default_medbw_kbps); 224b9c2ae6cSKrzysztof Kozlowski bwmon_set_threshold(bwmon, BWMON_THRESHOLD_LOW, 225b9c2ae6cSKrzysztof Kozlowski data->default_lowbw_kbps); 226b9c2ae6cSKrzysztof Kozlowski 227b9c2ae6cSKrzysztof Kozlowski thres_count = data->zone3_thres_count << BWMON_THRESHOLD_COUNT_ZONE3_SHIFT | 228b9c2ae6cSKrzysztof Kozlowski BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT << BWMON_THRESHOLD_COUNT_ZONE2_SHIFT | 229b9c2ae6cSKrzysztof Kozlowski data->zone1_thres_count << BWMON_THRESHOLD_COUNT_ZONE1_SHIFT | 230b9c2ae6cSKrzysztof Kozlowski BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT; 231b9c2ae6cSKrzysztof Kozlowski writel_relaxed(thres_count, bwmon->base + BWMON_THRESHOLD_COUNT); 232b9c2ae6cSKrzysztof Kozlowski writel_relaxed(BWMON_ZONE_ACTIONS_DEFAULT, 233b9c2ae6cSKrzysztof Kozlowski bwmon->base + BWMON_ZONE_ACTIONS); 234b9c2ae6cSKrzysztof Kozlowski /* Write barriers in bwmon_clear_irq() */ 235b9c2ae6cSKrzysztof Kozlowski 236b9c2ae6cSKrzysztof Kozlowski bwmon_clear_irq(bwmon); 237b9c2ae6cSKrzysztof Kozlowski bwmon_enable(bwmon, BWMON_IRQ_ENABLE_MASK); 238b9c2ae6cSKrzysztof Kozlowski } 239b9c2ae6cSKrzysztof Kozlowski 240b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr(int irq, void *dev_id) 241b9c2ae6cSKrzysztof Kozlowski { 242b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = dev_id; 243b9c2ae6cSKrzysztof Kozlowski unsigned int status, max; 244b9c2ae6cSKrzysztof Kozlowski int zone; 245b9c2ae6cSKrzysztof Kozlowski 246b9c2ae6cSKrzysztof Kozlowski status = readl(bwmon->base + BWMON_IRQ_STATUS); 247b9c2ae6cSKrzysztof Kozlowski status &= BWMON_IRQ_ENABLE_MASK; 248b9c2ae6cSKrzysztof Kozlowski if (!status) { 249b9c2ae6cSKrzysztof Kozlowski /* 250b9c2ae6cSKrzysztof Kozlowski * Only zone 1 and zone 3 interrupts are enabled but zone 2 251b9c2ae6cSKrzysztof Kozlowski * threshold could be hit and trigger interrupt even if not 252b9c2ae6cSKrzysztof Kozlowski * enabled. 253b9c2ae6cSKrzysztof Kozlowski * Such spurious interrupt might come with valuable max count or 254b9c2ae6cSKrzysztof Kozlowski * not, so solution would be to always check all 255b9c2ae6cSKrzysztof Kozlowski * BWMON_ZONE_MAX() registers to find the highest value. 256b9c2ae6cSKrzysztof Kozlowski * Such case is currently ignored. 257b9c2ae6cSKrzysztof Kozlowski */ 258b9c2ae6cSKrzysztof Kozlowski return IRQ_NONE; 259b9c2ae6cSKrzysztof Kozlowski } 260b9c2ae6cSKrzysztof Kozlowski 261b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon); 262b9c2ae6cSKrzysztof Kozlowski 263b9c2ae6cSKrzysztof Kozlowski zone = get_bitmask_order(status >> BWMON_IRQ_STATUS_ZONE_SHIFT) - 1; 264b9c2ae6cSKrzysztof Kozlowski /* 265b9c2ae6cSKrzysztof Kozlowski * Zone max bytes count register returns count units within sampling 266b9c2ae6cSKrzysztof Kozlowski * window. Downstream kernel for BWMONv4 (called BWMON type 2 in 267b9c2ae6cSKrzysztof Kozlowski * downstream) always increments the max bytes count by one. 268b9c2ae6cSKrzysztof Kozlowski */ 269b9c2ae6cSKrzysztof Kozlowski max = readl(bwmon->base + BWMON_ZONE_MAX(zone)) + 1; 270b9c2ae6cSKrzysztof Kozlowski max *= BWMON_COUNT_UNIT_KB; 271b9c2ae6cSKrzysztof Kozlowski bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->sample_ms); 272b9c2ae6cSKrzysztof Kozlowski 273b9c2ae6cSKrzysztof Kozlowski return IRQ_WAKE_THREAD; 274b9c2ae6cSKrzysztof Kozlowski } 275b9c2ae6cSKrzysztof Kozlowski 276b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr_thread(int irq, void *dev_id) 277b9c2ae6cSKrzysztof Kozlowski { 278b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = dev_id; 279b9c2ae6cSKrzysztof Kozlowski unsigned int irq_enable = 0; 280b9c2ae6cSKrzysztof Kozlowski struct dev_pm_opp *opp, *target_opp; 281b9c2ae6cSKrzysztof Kozlowski unsigned int bw_kbps, up_kbps, down_kbps; 282b9c2ae6cSKrzysztof Kozlowski 283b9c2ae6cSKrzysztof Kozlowski bw_kbps = bwmon->target_kbps; 284b9c2ae6cSKrzysztof Kozlowski 285b9c2ae6cSKrzysztof Kozlowski target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0); 286b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE) 287b9c2ae6cSKrzysztof Kozlowski target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0); 288b9c2ae6cSKrzysztof Kozlowski 289b9c2ae6cSKrzysztof Kozlowski bwmon->target_kbps = bw_kbps; 290b9c2ae6cSKrzysztof Kozlowski 291b9c2ae6cSKrzysztof Kozlowski bw_kbps--; 292b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0); 293b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE) 294b9c2ae6cSKrzysztof Kozlowski down_kbps = bwmon->target_kbps; 295b9c2ae6cSKrzysztof Kozlowski else 296b9c2ae6cSKrzysztof Kozlowski down_kbps = bw_kbps; 297b9c2ae6cSKrzysztof Kozlowski 298b9c2ae6cSKrzysztof Kozlowski up_kbps = bwmon->target_kbps + 1; 299b9c2ae6cSKrzysztof Kozlowski 300b9c2ae6cSKrzysztof Kozlowski if (bwmon->target_kbps >= bwmon->max_bw_kbps) 301b9c2ae6cSKrzysztof Kozlowski irq_enable = BIT(BWMON_IRQ_ENABLE_ZONE1_SHIFT); 302b9c2ae6cSKrzysztof Kozlowski else if (bwmon->target_kbps <= bwmon->min_bw_kbps) 303b9c2ae6cSKrzysztof Kozlowski irq_enable = BIT(BWMON_IRQ_ENABLE_ZONE3_SHIFT); 304b9c2ae6cSKrzysztof Kozlowski else 305b9c2ae6cSKrzysztof Kozlowski irq_enable = BWMON_IRQ_ENABLE_MASK; 306b9c2ae6cSKrzysztof Kozlowski 307b9c2ae6cSKrzysztof Kozlowski bwmon_set_threshold(bwmon, BWMON_THRESHOLD_HIGH, up_kbps); 308b9c2ae6cSKrzysztof Kozlowski bwmon_set_threshold(bwmon, BWMON_THRESHOLD_MED, down_kbps); 309b9c2ae6cSKrzysztof Kozlowski /* Write barriers in bwmon_clear_counters() */ 310b9c2ae6cSKrzysztof Kozlowski bwmon_clear_counters(bwmon); 311b9c2ae6cSKrzysztof Kozlowski bwmon_clear_irq(bwmon); 312b9c2ae6cSKrzysztof Kozlowski bwmon_enable(bwmon, irq_enable); 313b9c2ae6cSKrzysztof Kozlowski 314b9c2ae6cSKrzysztof Kozlowski if (bwmon->target_kbps == bwmon->current_kbps) 315b9c2ae6cSKrzysztof Kozlowski goto out; 316b9c2ae6cSKrzysztof Kozlowski 317b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_set_opp(bwmon->dev, target_opp); 318b9c2ae6cSKrzysztof Kozlowski bwmon->current_kbps = bwmon->target_kbps; 319b9c2ae6cSKrzysztof Kozlowski 320b9c2ae6cSKrzysztof Kozlowski out: 321b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_put(target_opp); 322b9c2ae6cSKrzysztof Kozlowski if (!IS_ERR(opp)) 323b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_put(opp); 324b9c2ae6cSKrzysztof Kozlowski 325b9c2ae6cSKrzysztof Kozlowski return IRQ_HANDLED; 326b9c2ae6cSKrzysztof Kozlowski } 327b9c2ae6cSKrzysztof Kozlowski 328b9c2ae6cSKrzysztof Kozlowski static int bwmon_probe(struct platform_device *pdev) 329b9c2ae6cSKrzysztof Kozlowski { 330b9c2ae6cSKrzysztof Kozlowski struct device *dev = &pdev->dev; 331b9c2ae6cSKrzysztof Kozlowski struct dev_pm_opp *opp; 332b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon; 333b9c2ae6cSKrzysztof Kozlowski const struct icc_bwmon_data *data; 334b9c2ae6cSKrzysztof Kozlowski int ret; 335b9c2ae6cSKrzysztof Kozlowski 336b9c2ae6cSKrzysztof Kozlowski bwmon = devm_kzalloc(dev, sizeof(*bwmon), GFP_KERNEL); 337b9c2ae6cSKrzysztof Kozlowski if (!bwmon) 338b9c2ae6cSKrzysztof Kozlowski return -ENOMEM; 339b9c2ae6cSKrzysztof Kozlowski 340b9c2ae6cSKrzysztof Kozlowski data = of_device_get_match_data(dev); 341b9c2ae6cSKrzysztof Kozlowski 342b9c2ae6cSKrzysztof Kozlowski bwmon->base = devm_platform_ioremap_resource(pdev, 0); 343b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(bwmon->base)) { 344b9c2ae6cSKrzysztof Kozlowski dev_err(dev, "failed to map bwmon registers\n"); 345b9c2ae6cSKrzysztof Kozlowski return PTR_ERR(bwmon->base); 346b9c2ae6cSKrzysztof Kozlowski } 347b9c2ae6cSKrzysztof Kozlowski 348b9c2ae6cSKrzysztof Kozlowski bwmon->irq = platform_get_irq(pdev, 0); 349947bb0d1SYang Li if (bwmon->irq < 0) 350b9c2ae6cSKrzysztof Kozlowski return bwmon->irq; 351b9c2ae6cSKrzysztof Kozlowski 352b9c2ae6cSKrzysztof Kozlowski ret = devm_pm_opp_of_add_table(dev); 353b9c2ae6cSKrzysztof Kozlowski if (ret) 354b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to add OPP table\n"); 355b9c2ae6cSKrzysztof Kozlowski 356b9c2ae6cSKrzysztof Kozlowski bwmon->max_bw_kbps = UINT_MAX; 357b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0); 358b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp)) 359b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to find max peak bandwidth\n"); 360b9c2ae6cSKrzysztof Kozlowski 361b9c2ae6cSKrzysztof Kozlowski bwmon->min_bw_kbps = 0; 362b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0); 363b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp)) 364b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to find min peak bandwidth\n"); 365b9c2ae6cSKrzysztof Kozlowski 366b9c2ae6cSKrzysztof Kozlowski bwmon->sample_ms = data->sample_ms; 367b9c2ae6cSKrzysztof Kozlowski bwmon->default_lowbw_kbps = data->default_lowbw_kbps; 368b9c2ae6cSKrzysztof Kozlowski bwmon->dev = dev; 369b9c2ae6cSKrzysztof Kozlowski 370b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon); 371b9c2ae6cSKrzysztof Kozlowski ret = devm_request_threaded_irq(dev, bwmon->irq, bwmon_intr, 372b9c2ae6cSKrzysztof Kozlowski bwmon_intr_thread, 373b9c2ae6cSKrzysztof Kozlowski IRQF_ONESHOT, dev_name(dev), bwmon); 374b9c2ae6cSKrzysztof Kozlowski if (ret) 375b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to request IRQ\n"); 376b9c2ae6cSKrzysztof Kozlowski 377b9c2ae6cSKrzysztof Kozlowski platform_set_drvdata(pdev, bwmon); 378b9c2ae6cSKrzysztof Kozlowski bwmon_start(bwmon, data); 379b9c2ae6cSKrzysztof Kozlowski 380b9c2ae6cSKrzysztof Kozlowski return 0; 381b9c2ae6cSKrzysztof Kozlowski } 382b9c2ae6cSKrzysztof Kozlowski 383b9c2ae6cSKrzysztof Kozlowski static int bwmon_remove(struct platform_device *pdev) 384b9c2ae6cSKrzysztof Kozlowski { 385b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = platform_get_drvdata(pdev); 386b9c2ae6cSKrzysztof Kozlowski 387b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon); 388b9c2ae6cSKrzysztof Kozlowski 389b9c2ae6cSKrzysztof Kozlowski return 0; 390b9c2ae6cSKrzysztof Kozlowski } 391b9c2ae6cSKrzysztof Kozlowski 392b9c2ae6cSKrzysztof Kozlowski /* BWMON v4 */ 393b9c2ae6cSKrzysztof Kozlowski static const struct icc_bwmon_data msm8998_bwmon_data = { 394b9c2ae6cSKrzysztof Kozlowski .sample_ms = 4, 395b9c2ae6cSKrzysztof Kozlowski .default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */ 396b9c2ae6cSKrzysztof Kozlowski .default_medbw_kbps = 512 * 1024, /* 512 MBps */ 397b9c2ae6cSKrzysztof Kozlowski .default_lowbw_kbps = 0, 398b9c2ae6cSKrzysztof Kozlowski .zone1_thres_count = 16, 399b9c2ae6cSKrzysztof Kozlowski .zone3_thres_count = 1, 400b9c2ae6cSKrzysztof Kozlowski }; 401b9c2ae6cSKrzysztof Kozlowski 402b9c2ae6cSKrzysztof Kozlowski static const struct of_device_id bwmon_of_match[] = { 403b9c2ae6cSKrzysztof Kozlowski { .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data }, 404b9c2ae6cSKrzysztof Kozlowski {} 405b9c2ae6cSKrzysztof Kozlowski }; 406b9c2ae6cSKrzysztof Kozlowski MODULE_DEVICE_TABLE(of, bwmon_of_match); 407b9c2ae6cSKrzysztof Kozlowski 408b9c2ae6cSKrzysztof Kozlowski static struct platform_driver bwmon_driver = { 409b9c2ae6cSKrzysztof Kozlowski .probe = bwmon_probe, 410b9c2ae6cSKrzysztof Kozlowski .remove = bwmon_remove, 411b9c2ae6cSKrzysztof Kozlowski .driver = { 412b9c2ae6cSKrzysztof Kozlowski .name = "qcom-bwmon", 413b9c2ae6cSKrzysztof Kozlowski .of_match_table = bwmon_of_match, 414b9c2ae6cSKrzysztof Kozlowski }, 415b9c2ae6cSKrzysztof Kozlowski }; 416b9c2ae6cSKrzysztof Kozlowski module_platform_driver(bwmon_driver); 417b9c2ae6cSKrzysztof Kozlowski 418b9c2ae6cSKrzysztof Kozlowski MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>"); 419b9c2ae6cSKrzysztof Kozlowski MODULE_DESCRIPTION("QCOM BWMON driver"); 420b9c2ae6cSKrzysztof Kozlowski MODULE_LICENSE("GPL"); 421