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>
156484be9dSRob Herring #include <linux/of.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 u8 zone1_thres_count;
169b9c2ae6cSKrzysztof Kozlowski u8 zone3_thres_count;
170e6f34184SKrzysztof Kozlowski unsigned int quirks;
171ec63dcd3SKrzysztof Kozlowski
172ec63dcd3SKrzysztof Kozlowski const struct regmap_config *regmap_cfg;
173ec63dcd3SKrzysztof Kozlowski const struct reg_field *regmap_fields;
174b6e9fb7aSKonrad Dybcio
175b6e9fb7aSKonrad Dybcio const struct regmap_config *global_regmap_cfg;
176b6e9fb7aSKonrad Dybcio const struct reg_field *global_regmap_fields;
177b9c2ae6cSKrzysztof Kozlowski };
178b9c2ae6cSKrzysztof Kozlowski
179b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon {
180b9c2ae6cSKrzysztof Kozlowski struct device *dev;
1811dd5246eSKrzysztof Kozlowski const struct icc_bwmon_data *data;
182b9c2ae6cSKrzysztof Kozlowski int irq;
183b9c2ae6cSKrzysztof Kozlowski
184ec63dcd3SKrzysztof Kozlowski struct regmap_field *regs[F_NUM_FIELDS];
185b6e9fb7aSKonrad Dybcio struct regmap_field *global_regs[F_NUM_GLOBAL_FIELDS];
186ec63dcd3SKrzysztof Kozlowski
187b9c2ae6cSKrzysztof Kozlowski unsigned int max_bw_kbps;
188b9c2ae6cSKrzysztof Kozlowski unsigned int min_bw_kbps;
189b9c2ae6cSKrzysztof Kozlowski unsigned int target_kbps;
190b9c2ae6cSKrzysztof Kozlowski unsigned int current_kbps;
191b9c2ae6cSKrzysztof Kozlowski };
192b9c2ae6cSKrzysztof Kozlowski
193ec63dcd3SKrzysztof Kozlowski /* BWMON v4 */
194ec63dcd3SKrzysztof Kozlowski static const struct reg_field msm8998_bwmon_reg_fields[] = {
195b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_CLEAR] = {},
196b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_ENABLE] = {},
197ec63dcd3SKrzysztof Kozlowski [F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7),
198ec63dcd3SKrzysztof Kozlowski [F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7),
199ec63dcd3SKrzysztof Kozlowski [F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7),
200ec63dcd3SKrzysztof Kozlowski /* F_ENABLE covers entire register to disable other features */
201ec63dcd3SKrzysztof Kozlowski [F_ENABLE] = REG_FIELD(BWMON_V4_ENABLE, 0, 31),
202ec63dcd3SKrzysztof Kozlowski [F_CLEAR] = REG_FIELD(BWMON_V4_CLEAR, 0, 1),
203ec63dcd3SKrzysztof Kozlowski [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23),
204ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11),
205ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_MED] = REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11),
206ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11),
207ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7),
208ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15),
209ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23),
210ec63dcd3SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31),
211ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7),
212ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15),
213ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23),
214ec63dcd3SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31),
215ec63dcd3SKrzysztof Kozlowski [F_ZONE0_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11),
216ec63dcd3SKrzysztof Kozlowski [F_ZONE1_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11),
217ec63dcd3SKrzysztof Kozlowski [F_ZONE2_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11),
218ec63dcd3SKrzysztof Kozlowski [F_ZONE3_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11),
219ec63dcd3SKrzysztof Kozlowski };
220ec63dcd3SKrzysztof Kozlowski
221ec63dcd3SKrzysztof Kozlowski static const struct regmap_range msm8998_bwmon_reg_noread_ranges[] = {
222ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR),
223ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR),
224ec63dcd3SKrzysztof Kozlowski };
225ec63dcd3SKrzysztof Kozlowski
226ec63dcd3SKrzysztof Kozlowski static const struct regmap_access_table msm8998_bwmon_reg_read_table = {
227ec63dcd3SKrzysztof Kozlowski .no_ranges = msm8998_bwmon_reg_noread_ranges,
228ec63dcd3SKrzysztof Kozlowski .n_no_ranges = ARRAY_SIZE(msm8998_bwmon_reg_noread_ranges),
229ec63dcd3SKrzysztof Kozlowski };
230ec63dcd3SKrzysztof Kozlowski
231ec63dcd3SKrzysztof Kozlowski static const struct regmap_range msm8998_bwmon_reg_volatile_ranges[] = {
232ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_IRQ_STATUS, BWMON_V4_IRQ_STATUS),
233ec63dcd3SKrzysztof Kozlowski regmap_reg_range(BWMON_V4_ZONE_MAX(0), BWMON_V4_ZONE_MAX(3)),
234ec63dcd3SKrzysztof Kozlowski };
235ec63dcd3SKrzysztof Kozlowski
236ec63dcd3SKrzysztof Kozlowski static const struct regmap_access_table msm8998_bwmon_reg_volatile_table = {
237ec63dcd3SKrzysztof Kozlowski .yes_ranges = msm8998_bwmon_reg_volatile_ranges,
238ec63dcd3SKrzysztof Kozlowski .n_yes_ranges = ARRAY_SIZE(msm8998_bwmon_reg_volatile_ranges),
239ec63dcd3SKrzysztof Kozlowski };
240ec63dcd3SKrzysztof Kozlowski
241b6e9fb7aSKonrad Dybcio static const struct reg_field msm8998_bwmon_global_reg_fields[] = {
242b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR, 0, 0),
243b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE, 0, 0),
244b6e9fb7aSKonrad Dybcio };
245b6e9fb7aSKonrad Dybcio
246b6e9fb7aSKonrad Dybcio static const struct regmap_range msm8998_bwmon_global_reg_noread_ranges[] = {
247b6e9fb7aSKonrad Dybcio regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR, BWMON_V4_GLOBAL_IRQ_CLEAR),
248b6e9fb7aSKonrad Dybcio };
249b6e9fb7aSKonrad Dybcio
250b6e9fb7aSKonrad Dybcio static const struct regmap_access_table msm8998_bwmon_global_reg_read_table = {
251b6e9fb7aSKonrad Dybcio .no_ranges = msm8998_bwmon_global_reg_noread_ranges,
252b6e9fb7aSKonrad Dybcio .n_no_ranges = ARRAY_SIZE(msm8998_bwmon_global_reg_noread_ranges),
253b6e9fb7aSKonrad Dybcio };
254b6e9fb7aSKonrad Dybcio
255ec63dcd3SKrzysztof Kozlowski /*
256ec63dcd3SKrzysztof Kozlowski * Fill the cache for non-readable registers only as rest does not really
257ec63dcd3SKrzysztof Kozlowski * matter and can be read from the device.
258ec63dcd3SKrzysztof Kozlowski */
259ec63dcd3SKrzysztof Kozlowski static const struct reg_default msm8998_bwmon_reg_defaults[] = {
260ec63dcd3SKrzysztof Kozlowski { BWMON_V4_IRQ_CLEAR, 0x0 },
261ec63dcd3SKrzysztof Kozlowski { BWMON_V4_CLEAR, 0x0 },
262ec63dcd3SKrzysztof Kozlowski };
263ec63dcd3SKrzysztof Kozlowski
264b6e9fb7aSKonrad Dybcio static const struct reg_default msm8998_bwmon_global_reg_defaults[] = {
265b6e9fb7aSKonrad Dybcio { BWMON_V4_GLOBAL_IRQ_CLEAR, 0x0 },
266b6e9fb7aSKonrad Dybcio };
267b6e9fb7aSKonrad Dybcio
268ec63dcd3SKrzysztof Kozlowski static const struct regmap_config msm8998_bwmon_regmap_cfg = {
269ec63dcd3SKrzysztof Kozlowski .reg_bits = 32,
270ec63dcd3SKrzysztof Kozlowski .reg_stride = 4,
271ec63dcd3SKrzysztof Kozlowski .val_bits = 32,
272ec63dcd3SKrzysztof Kozlowski /*
273ec63dcd3SKrzysztof Kozlowski * No concurrent access expected - driver has one interrupt handler,
274ec63dcd3SKrzysztof Kozlowski * regmap is not shared, no driver or user-space API.
275ec63dcd3SKrzysztof Kozlowski */
276ec63dcd3SKrzysztof Kozlowski .disable_locking = true,
277ec63dcd3SKrzysztof Kozlowski .rd_table = &msm8998_bwmon_reg_read_table,
278ec63dcd3SKrzysztof Kozlowski .volatile_table = &msm8998_bwmon_reg_volatile_table,
279ec63dcd3SKrzysztof Kozlowski .reg_defaults = msm8998_bwmon_reg_defaults,
280ec63dcd3SKrzysztof Kozlowski .num_reg_defaults = ARRAY_SIZE(msm8998_bwmon_reg_defaults),
281ec63dcd3SKrzysztof Kozlowski /*
282ec63dcd3SKrzysztof Kozlowski * Cache is necessary for using regmap fields with non-readable
283ec63dcd3SKrzysztof Kozlowski * registers.
284ec63dcd3SKrzysztof Kozlowski */
285ec63dcd3SKrzysztof Kozlowski .cache_type = REGCACHE_RBTREE,
286ec63dcd3SKrzysztof Kozlowski };
287ec63dcd3SKrzysztof Kozlowski
288b6e9fb7aSKonrad Dybcio static const struct regmap_config msm8998_bwmon_global_regmap_cfg = {
289b6e9fb7aSKonrad Dybcio .reg_bits = 32,
290b6e9fb7aSKonrad Dybcio .reg_stride = 4,
291b6e9fb7aSKonrad Dybcio .val_bits = 32,
292b6e9fb7aSKonrad Dybcio /*
293b6e9fb7aSKonrad Dybcio * No concurrent access expected - driver has one interrupt handler,
294b6e9fb7aSKonrad Dybcio * regmap is not shared, no driver or user-space API.
295b6e9fb7aSKonrad Dybcio */
296b6e9fb7aSKonrad Dybcio .disable_locking = true,
297b6e9fb7aSKonrad Dybcio .rd_table = &msm8998_bwmon_global_reg_read_table,
298b6e9fb7aSKonrad Dybcio .reg_defaults = msm8998_bwmon_global_reg_defaults,
299b6e9fb7aSKonrad Dybcio .num_reg_defaults = ARRAY_SIZE(msm8998_bwmon_global_reg_defaults),
300b6e9fb7aSKonrad Dybcio /*
301b6e9fb7aSKonrad Dybcio * Cache is necessary for using regmap fields with non-readable
302b6e9fb7aSKonrad Dybcio * registers.
303b6e9fb7aSKonrad Dybcio */
304b6e9fb7aSKonrad Dybcio .cache_type = REGCACHE_RBTREE,
305b6e9fb7aSKonrad Dybcio };
306b6e9fb7aSKonrad Dybcio
307b6e9fb7aSKonrad Dybcio static const struct reg_field sdm845_cpu_bwmon_reg_fields[] = {
308b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_CLEAR] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0, 0),
309b6e9fb7aSKonrad Dybcio [F_GLOBAL_IRQ_ENABLE] = REG_FIELD(BWMON_V4_GLOBAL_IRQ_ENABLE_845, 0, 0),
310b6e9fb7aSKonrad Dybcio [F_IRQ_STATUS] = REG_FIELD(BWMON_V4_IRQ_STATUS, 4, 7),
311b6e9fb7aSKonrad Dybcio [F_IRQ_CLEAR] = REG_FIELD(BWMON_V4_IRQ_CLEAR, 4, 7),
312b6e9fb7aSKonrad Dybcio [F_IRQ_ENABLE] = REG_FIELD(BWMON_V4_IRQ_ENABLE, 4, 7),
313b6e9fb7aSKonrad Dybcio /* F_ENABLE covers entire register to disable other features */
314b6e9fb7aSKonrad Dybcio [F_ENABLE] = REG_FIELD(BWMON_V4_ENABLE, 0, 31),
315b6e9fb7aSKonrad Dybcio [F_CLEAR] = REG_FIELD(BWMON_V4_CLEAR, 0, 1),
316b6e9fb7aSKonrad Dybcio [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V4_SAMPLE_WINDOW, 0, 23),
317b6e9fb7aSKonrad Dybcio [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V4_THRESHOLD_HIGH, 0, 11),
318b6e9fb7aSKonrad Dybcio [F_THRESHOLD_MED] = REG_FIELD(BWMON_V4_THRESHOLD_MED, 0, 11),
319b6e9fb7aSKonrad Dybcio [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V4_THRESHOLD_LOW, 0, 11),
320b6e9fb7aSKonrad Dybcio [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 0, 7),
321b6e9fb7aSKonrad Dybcio [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 8, 15),
322b6e9fb7aSKonrad Dybcio [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 16, 23),
323b6e9fb7aSKonrad Dybcio [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V4_ZONE_ACTIONS, 24, 31),
324b6e9fb7aSKonrad Dybcio [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 0, 7),
325b6e9fb7aSKonrad Dybcio [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 8, 15),
326b6e9fb7aSKonrad Dybcio [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 16, 23),
327b6e9fb7aSKonrad Dybcio [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V4_THRESHOLD_COUNT, 24, 31),
328b6e9fb7aSKonrad Dybcio [F_ZONE0_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(0), 0, 11),
329b6e9fb7aSKonrad Dybcio [F_ZONE1_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(1), 0, 11),
330b6e9fb7aSKonrad Dybcio [F_ZONE2_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(2), 0, 11),
331b6e9fb7aSKonrad Dybcio [F_ZONE3_MAX] = REG_FIELD(BWMON_V4_ZONE_MAX(3), 0, 11),
332b6e9fb7aSKonrad Dybcio };
333b6e9fb7aSKonrad Dybcio
334b6e9fb7aSKonrad Dybcio static const struct regmap_range sdm845_cpu_bwmon_reg_noread_ranges[] = {
335b6e9fb7aSKonrad Dybcio regmap_reg_range(BWMON_V4_GLOBAL_IRQ_CLEAR_845, BWMON_V4_GLOBAL_IRQ_CLEAR_845),
336b6e9fb7aSKonrad Dybcio regmap_reg_range(BWMON_V4_IRQ_CLEAR, BWMON_V4_IRQ_CLEAR),
337b6e9fb7aSKonrad Dybcio regmap_reg_range(BWMON_V4_CLEAR, BWMON_V4_CLEAR),
338b6e9fb7aSKonrad Dybcio };
339b6e9fb7aSKonrad Dybcio
340b6e9fb7aSKonrad Dybcio static const struct regmap_access_table sdm845_cpu_bwmon_reg_read_table = {
341b6e9fb7aSKonrad Dybcio .no_ranges = sdm845_cpu_bwmon_reg_noread_ranges,
342b6e9fb7aSKonrad Dybcio .n_no_ranges = ARRAY_SIZE(sdm845_cpu_bwmon_reg_noread_ranges),
343b6e9fb7aSKonrad Dybcio };
344b6e9fb7aSKonrad Dybcio
345b6e9fb7aSKonrad Dybcio /*
346b6e9fb7aSKonrad Dybcio * Fill the cache for non-readable registers only as rest does not really
347b6e9fb7aSKonrad Dybcio * matter and can be read from the device.
348b6e9fb7aSKonrad Dybcio */
349b6e9fb7aSKonrad Dybcio static const struct reg_default sdm845_cpu_bwmon_reg_defaults[] = {
350b6e9fb7aSKonrad Dybcio { BWMON_V4_GLOBAL_IRQ_CLEAR_845, 0x0 },
351b6e9fb7aSKonrad Dybcio { BWMON_V4_IRQ_CLEAR, 0x0 },
352b6e9fb7aSKonrad Dybcio { BWMON_V4_CLEAR, 0x0 },
353b6e9fb7aSKonrad Dybcio };
354b6e9fb7aSKonrad Dybcio
355b6e9fb7aSKonrad Dybcio static const struct regmap_config sdm845_cpu_bwmon_regmap_cfg = {
356b6e9fb7aSKonrad Dybcio .reg_bits = 32,
357b6e9fb7aSKonrad Dybcio .reg_stride = 4,
358b6e9fb7aSKonrad Dybcio .val_bits = 32,
359b6e9fb7aSKonrad Dybcio /*
360b6e9fb7aSKonrad Dybcio * No concurrent access expected - driver has one interrupt handler,
361b6e9fb7aSKonrad Dybcio * regmap is not shared, no driver or user-space API.
362b6e9fb7aSKonrad Dybcio */
363b6e9fb7aSKonrad Dybcio .disable_locking = true,
364b6e9fb7aSKonrad Dybcio .rd_table = &sdm845_cpu_bwmon_reg_read_table,
365b6e9fb7aSKonrad Dybcio .volatile_table = &msm8998_bwmon_reg_volatile_table,
366b6e9fb7aSKonrad Dybcio .reg_defaults = sdm845_cpu_bwmon_reg_defaults,
367b6e9fb7aSKonrad Dybcio .num_reg_defaults = ARRAY_SIZE(sdm845_cpu_bwmon_reg_defaults),
368b6e9fb7aSKonrad Dybcio /*
369b6e9fb7aSKonrad Dybcio * Cache is necessary for using regmap fields with non-readable
370b6e9fb7aSKonrad Dybcio * registers.
371b6e9fb7aSKonrad Dybcio */
372b6e9fb7aSKonrad Dybcio .cache_type = REGCACHE_RBTREE,
373b6e9fb7aSKonrad Dybcio };
374b6e9fb7aSKonrad Dybcio
37514af4ce0SKrzysztof Kozlowski /* BWMON v5 */
37614af4ce0SKrzysztof Kozlowski static const struct reg_field sdm845_llcc_bwmon_reg_fields[] = {
37714af4ce0SKrzysztof Kozlowski [F_GLOBAL_IRQ_CLEAR] = {},
37814af4ce0SKrzysztof Kozlowski [F_GLOBAL_IRQ_ENABLE] = {},
37914af4ce0SKrzysztof Kozlowski [F_IRQ_STATUS] = REG_FIELD(BWMON_V5_IRQ_STATUS, 0, 3),
38014af4ce0SKrzysztof Kozlowski [F_IRQ_CLEAR] = REG_FIELD(BWMON_V5_IRQ_CLEAR, 0, 3),
38114af4ce0SKrzysztof Kozlowski [F_IRQ_ENABLE] = REG_FIELD(BWMON_V5_IRQ_ENABLE, 0, 3),
38214af4ce0SKrzysztof Kozlowski /* F_ENABLE covers entire register to disable other features */
38314af4ce0SKrzysztof Kozlowski [F_ENABLE] = REG_FIELD(BWMON_V5_ENABLE, 0, 31),
38414af4ce0SKrzysztof Kozlowski [F_CLEAR] = REG_FIELD(BWMON_V5_CLEAR, 0, 1),
38514af4ce0SKrzysztof Kozlowski [F_SAMPLE_WINDOW] = REG_FIELD(BWMON_V5_SAMPLE_WINDOW, 0, 19),
38614af4ce0SKrzysztof Kozlowski [F_THRESHOLD_HIGH] = REG_FIELD(BWMON_V5_THRESHOLD_HIGH, 0, 11),
38714af4ce0SKrzysztof Kozlowski [F_THRESHOLD_MED] = REG_FIELD(BWMON_V5_THRESHOLD_MED, 0, 11),
38814af4ce0SKrzysztof Kozlowski [F_THRESHOLD_LOW] = REG_FIELD(BWMON_V5_THRESHOLD_LOW, 0, 11),
38914af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE0] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 0, 7),
39014af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE1] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 8, 15),
39114af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE2] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 16, 23),
39214af4ce0SKrzysztof Kozlowski [F_ZONE_ACTIONS_ZONE3] = REG_FIELD(BWMON_V5_ZONE_ACTIONS, 24, 31),
39314af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE0] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 0, 7),
39414af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE1] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 8, 15),
39514af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE2] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 16, 23),
39614af4ce0SKrzysztof Kozlowski [F_THRESHOLD_COUNT_ZONE3] = REG_FIELD(BWMON_V5_THRESHOLD_COUNT, 24, 31),
39714af4ce0SKrzysztof Kozlowski [F_ZONE0_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(0), 0, 11),
39814af4ce0SKrzysztof Kozlowski [F_ZONE1_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(1), 0, 11),
39914af4ce0SKrzysztof Kozlowski [F_ZONE2_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(2), 0, 11),
40014af4ce0SKrzysztof Kozlowski [F_ZONE3_MAX] = REG_FIELD(BWMON_V5_ZONE_MAX(3), 0, 11),
40114af4ce0SKrzysztof Kozlowski };
40214af4ce0SKrzysztof Kozlowski
40314af4ce0SKrzysztof Kozlowski static const struct regmap_range sdm845_llcc_bwmon_reg_noread_ranges[] = {
40414af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_IRQ_CLEAR, BWMON_V5_IRQ_CLEAR),
40514af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_CLEAR, BWMON_V5_CLEAR),
40614af4ce0SKrzysztof Kozlowski };
40714af4ce0SKrzysztof Kozlowski
40814af4ce0SKrzysztof Kozlowski static const struct regmap_access_table sdm845_llcc_bwmon_reg_read_table = {
40914af4ce0SKrzysztof Kozlowski .no_ranges = sdm845_llcc_bwmon_reg_noread_ranges,
41014af4ce0SKrzysztof Kozlowski .n_no_ranges = ARRAY_SIZE(sdm845_llcc_bwmon_reg_noread_ranges),
41114af4ce0SKrzysztof Kozlowski };
41214af4ce0SKrzysztof Kozlowski
41314af4ce0SKrzysztof Kozlowski static const struct regmap_range sdm845_llcc_bwmon_reg_volatile_ranges[] = {
41414af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_IRQ_STATUS, BWMON_V5_IRQ_STATUS),
41514af4ce0SKrzysztof Kozlowski regmap_reg_range(BWMON_V5_ZONE_MAX(0), BWMON_V5_ZONE_MAX(3)),
41614af4ce0SKrzysztof Kozlowski };
41714af4ce0SKrzysztof Kozlowski
41814af4ce0SKrzysztof Kozlowski static const struct regmap_access_table sdm845_llcc_bwmon_reg_volatile_table = {
41914af4ce0SKrzysztof Kozlowski .yes_ranges = sdm845_llcc_bwmon_reg_volatile_ranges,
42014af4ce0SKrzysztof Kozlowski .n_yes_ranges = ARRAY_SIZE(sdm845_llcc_bwmon_reg_volatile_ranges),
42114af4ce0SKrzysztof Kozlowski };
42214af4ce0SKrzysztof Kozlowski
42314af4ce0SKrzysztof Kozlowski /*
42414af4ce0SKrzysztof Kozlowski * Fill the cache for non-readable registers only as rest does not really
42514af4ce0SKrzysztof Kozlowski * matter and can be read from the device.
42614af4ce0SKrzysztof Kozlowski */
42714af4ce0SKrzysztof Kozlowski static const struct reg_default sdm845_llcc_bwmon_reg_defaults[] = {
42814af4ce0SKrzysztof Kozlowski { BWMON_V5_IRQ_CLEAR, 0x0 },
42914af4ce0SKrzysztof Kozlowski { BWMON_V5_CLEAR, 0x0 },
43014af4ce0SKrzysztof Kozlowski };
43114af4ce0SKrzysztof Kozlowski
43214af4ce0SKrzysztof Kozlowski static const struct regmap_config sdm845_llcc_bwmon_regmap_cfg = {
43314af4ce0SKrzysztof Kozlowski .reg_bits = 32,
43414af4ce0SKrzysztof Kozlowski .reg_stride = 4,
43514af4ce0SKrzysztof Kozlowski .val_bits = 32,
43614af4ce0SKrzysztof Kozlowski /*
43714af4ce0SKrzysztof Kozlowski * No concurrent access expected - driver has one interrupt handler,
43814af4ce0SKrzysztof Kozlowski * regmap is not shared, no driver or user-space API.
43914af4ce0SKrzysztof Kozlowski */
44014af4ce0SKrzysztof Kozlowski .disable_locking = true,
44114af4ce0SKrzysztof Kozlowski .rd_table = &sdm845_llcc_bwmon_reg_read_table,
44214af4ce0SKrzysztof Kozlowski .volatile_table = &sdm845_llcc_bwmon_reg_volatile_table,
44314af4ce0SKrzysztof Kozlowski .reg_defaults = sdm845_llcc_bwmon_reg_defaults,
44414af4ce0SKrzysztof Kozlowski .num_reg_defaults = ARRAY_SIZE(sdm845_llcc_bwmon_reg_defaults),
44514af4ce0SKrzysztof Kozlowski /*
44614af4ce0SKrzysztof Kozlowski * Cache is necessary for using regmap fields with non-readable
44714af4ce0SKrzysztof Kozlowski * registers.
44814af4ce0SKrzysztof Kozlowski */
44914af4ce0SKrzysztof Kozlowski .cache_type = REGCACHE_RBTREE,
45014af4ce0SKrzysztof Kozlowski };
45114af4ce0SKrzysztof Kozlowski
bwmon_clear_counters(struct icc_bwmon * bwmon,bool clear_all)452956deab5SKrzysztof Kozlowski static void bwmon_clear_counters(struct icc_bwmon *bwmon, bool clear_all)
453b9c2ae6cSKrzysztof Kozlowski {
454956deab5SKrzysztof Kozlowski unsigned int val = BWMON_CLEAR_CLEAR;
455956deab5SKrzysztof Kozlowski
456956deab5SKrzysztof Kozlowski if (clear_all)
457956deab5SKrzysztof Kozlowski val |= BWMON_CLEAR_CLEAR_ALL;
458b9c2ae6cSKrzysztof Kozlowski /*
459b9c2ae6cSKrzysztof Kozlowski * Clear counters. The order and barriers are
460b9c2ae6cSKrzysztof Kozlowski * important. Quoting downstream Qualcomm msm-4.9 tree:
461b9c2ae6cSKrzysztof Kozlowski *
462b9c2ae6cSKrzysztof Kozlowski * The counter clear and IRQ clear bits are not in the same 4KB
463b9c2ae6cSKrzysztof Kozlowski * region. So, we need to make sure the counter clear is completed
464b9c2ae6cSKrzysztof Kozlowski * before we try to clear the IRQ or do any other counter operations.
465b9c2ae6cSKrzysztof Kozlowski */
466ec63dcd3SKrzysztof Kozlowski regmap_field_force_write(bwmon->regs[F_CLEAR], val);
467cdad59c2SRajendra Nayak if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR)
468cdad59c2SRajendra Nayak regmap_field_force_write(bwmon->regs[F_CLEAR], 0);
469b9c2ae6cSKrzysztof Kozlowski }
470b9c2ae6cSKrzysztof Kozlowski
bwmon_clear_irq(struct icc_bwmon * bwmon)471b9c2ae6cSKrzysztof Kozlowski static void bwmon_clear_irq(struct icc_bwmon *bwmon)
472b9c2ae6cSKrzysztof Kozlowski {
473b6e9fb7aSKonrad Dybcio struct regmap_field *global_irq_clr;
474b6e9fb7aSKonrad Dybcio
475b6e9fb7aSKonrad Dybcio if (bwmon->data->global_regmap_fields)
476b6e9fb7aSKonrad Dybcio global_irq_clr = bwmon->global_regs[F_GLOBAL_IRQ_CLEAR];
477b6e9fb7aSKonrad Dybcio else
478b6e9fb7aSKonrad Dybcio global_irq_clr = bwmon->regs[F_GLOBAL_IRQ_CLEAR];
479b6e9fb7aSKonrad Dybcio
480b9c2ae6cSKrzysztof Kozlowski /*
481b9c2ae6cSKrzysztof Kozlowski * Clear zone and global interrupts. The order and barriers are
482b9c2ae6cSKrzysztof Kozlowski * important. Quoting downstream Qualcomm msm-4.9 tree:
483b9c2ae6cSKrzysztof Kozlowski *
484b9c2ae6cSKrzysztof Kozlowski * Synchronize the local interrupt clear in mon_irq_clear()
485b9c2ae6cSKrzysztof Kozlowski * with the global interrupt clear here. Otherwise, the CPU
486b9c2ae6cSKrzysztof Kozlowski * may reorder the two writes and clear the global interrupt
487b9c2ae6cSKrzysztof Kozlowski * before the local interrupt, causing the global interrupt
488b9c2ae6cSKrzysztof Kozlowski * to be retriggered by the local interrupt still being high.
489b9c2ae6cSKrzysztof Kozlowski *
490b9c2ae6cSKrzysztof Kozlowski * Similarly, because the global registers are in a different
491b9c2ae6cSKrzysztof Kozlowski * region than the local registers, we need to ensure any register
492b9c2ae6cSKrzysztof Kozlowski * writes to enable the monitor after this call are ordered with the
493b9c2ae6cSKrzysztof Kozlowski * clearing here so that local writes don't happen before the
494b9c2ae6cSKrzysztof Kozlowski * interrupt is cleared.
495b9c2ae6cSKrzysztof Kozlowski */
496ec63dcd3SKrzysztof Kozlowski regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], BWMON_IRQ_ENABLE_MASK);
497cdad59c2SRajendra Nayak if (bwmon->data->quirks & BWMON_NEEDS_FORCE_CLEAR)
498cdad59c2SRajendra Nayak regmap_field_force_write(bwmon->regs[F_IRQ_CLEAR], 0);
499e6f34184SKrzysztof Kozlowski if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
500b6e9fb7aSKonrad Dybcio regmap_field_force_write(global_irq_clr,
501ec63dcd3SKrzysztof Kozlowski BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
502b9c2ae6cSKrzysztof Kozlowski }
503b9c2ae6cSKrzysztof Kozlowski
bwmon_disable(struct icc_bwmon * bwmon)504b9c2ae6cSKrzysztof Kozlowski static void bwmon_disable(struct icc_bwmon *bwmon)
505b9c2ae6cSKrzysztof Kozlowski {
506b6e9fb7aSKonrad Dybcio struct regmap_field *global_irq_en;
507b6e9fb7aSKonrad Dybcio
508b6e9fb7aSKonrad Dybcio if (bwmon->data->global_regmap_fields)
509b6e9fb7aSKonrad Dybcio global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE];
510b6e9fb7aSKonrad Dybcio else
511b6e9fb7aSKonrad Dybcio global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE];
512b6e9fb7aSKonrad Dybcio
513b9c2ae6cSKrzysztof Kozlowski /* Disable interrupts. Strict ordering, see bwmon_clear_irq(). */
514e6f34184SKrzysztof Kozlowski if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
515b6e9fb7aSKonrad Dybcio regmap_field_write(global_irq_en, 0x0);
516ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_IRQ_ENABLE], 0x0);
517b9c2ae6cSKrzysztof Kozlowski
518b9c2ae6cSKrzysztof Kozlowski /*
519b9c2ae6cSKrzysztof Kozlowski * Disable bwmon. Must happen before bwmon_clear_irq() to avoid spurious
520b9c2ae6cSKrzysztof Kozlowski * IRQ.
521b9c2ae6cSKrzysztof Kozlowski */
522ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ENABLE], 0x0);
523b9c2ae6cSKrzysztof Kozlowski }
524b9c2ae6cSKrzysztof Kozlowski
bwmon_enable(struct icc_bwmon * bwmon,unsigned int irq_enable)525b9c2ae6cSKrzysztof Kozlowski static void bwmon_enable(struct icc_bwmon *bwmon, unsigned int irq_enable)
526b9c2ae6cSKrzysztof Kozlowski {
527b6e9fb7aSKonrad Dybcio struct regmap_field *global_irq_en;
528b6e9fb7aSKonrad Dybcio
529b6e9fb7aSKonrad Dybcio if (bwmon->data->global_regmap_fields)
530b6e9fb7aSKonrad Dybcio global_irq_en = bwmon->global_regs[F_GLOBAL_IRQ_ENABLE];
531b6e9fb7aSKonrad Dybcio else
532b6e9fb7aSKonrad Dybcio global_irq_en = bwmon->regs[F_GLOBAL_IRQ_ENABLE];
533b6e9fb7aSKonrad Dybcio
534b9c2ae6cSKrzysztof Kozlowski /* Enable interrupts */
535e6f34184SKrzysztof Kozlowski if (bwmon->data->quirks & BWMON_HAS_GLOBAL_IRQ)
536b6e9fb7aSKonrad Dybcio regmap_field_write(global_irq_en,
537ec63dcd3SKrzysztof Kozlowski BWMON_V4_GLOBAL_IRQ_ENABLE_ENABLE);
538b6e9fb7aSKonrad Dybcio
539ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_IRQ_ENABLE], irq_enable);
540b9c2ae6cSKrzysztof Kozlowski
541b9c2ae6cSKrzysztof Kozlowski /* Enable bwmon */
542ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ENABLE], BWMON_ENABLE_ENABLE);
543b9c2ae6cSKrzysztof Kozlowski }
544b9c2ae6cSKrzysztof Kozlowski
bwmon_kbps_to_count(struct icc_bwmon * bwmon,unsigned int kbps)545650db9faSKrzysztof Kozlowski static unsigned int bwmon_kbps_to_count(struct icc_bwmon *bwmon,
546650db9faSKrzysztof Kozlowski unsigned int kbps)
547b9c2ae6cSKrzysztof Kozlowski {
548650db9faSKrzysztof Kozlowski return kbps / bwmon->data->count_unit_kb;
549b9c2ae6cSKrzysztof Kozlowski }
550b9c2ae6cSKrzysztof Kozlowski
bwmon_set_threshold(struct icc_bwmon * bwmon,struct regmap_field * reg,unsigned int kbps)551ec63dcd3SKrzysztof Kozlowski static void bwmon_set_threshold(struct icc_bwmon *bwmon,
552ec63dcd3SKrzysztof Kozlowski struct regmap_field *reg, unsigned int kbps)
553b9c2ae6cSKrzysztof Kozlowski {
554b9c2ae6cSKrzysztof Kozlowski unsigned int thres;
555b9c2ae6cSKrzysztof Kozlowski
556650db9faSKrzysztof Kozlowski thres = mult_frac(bwmon_kbps_to_count(bwmon, kbps),
557650db9faSKrzysztof Kozlowski bwmon->data->sample_ms, MSEC_PER_SEC);
558ec63dcd3SKrzysztof Kozlowski regmap_field_write(reg, thres);
559b9c2ae6cSKrzysztof Kozlowski }
560b9c2ae6cSKrzysztof Kozlowski
bwmon_start(struct icc_bwmon * bwmon)5611dd5246eSKrzysztof Kozlowski static void bwmon_start(struct icc_bwmon *bwmon)
562b9c2ae6cSKrzysztof Kozlowski {
5631dd5246eSKrzysztof Kozlowski const struct icc_bwmon_data *data = bwmon->data;
5640276f69fSKonrad Dybcio u32 bw_low = 0;
565b9c2ae6cSKrzysztof Kozlowski int window;
566b9c2ae6cSKrzysztof Kozlowski
5670276f69fSKonrad Dybcio /* No need to check for errors, as this must have succeeded before. */
568*aad41f4cSSibi Sankar dev_pm_opp_put(dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_low, 0));
5690276f69fSKonrad Dybcio
570956deab5SKrzysztof Kozlowski bwmon_clear_counters(bwmon, true);
571b9c2ae6cSKrzysztof Kozlowski
5721dd5246eSKrzysztof Kozlowski window = mult_frac(bwmon->data->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC);
57314af4ce0SKrzysztof Kozlowski /* Maximum sampling window: 0xffffff for v4 and 0xfffff for v5 */
574ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_SAMPLE_WINDOW], window);
575b9c2ae6cSKrzysztof Kozlowski
5760276f69fSKonrad Dybcio bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], bw_low);
5770276f69fSKonrad Dybcio bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], bw_low);
5780276f69fSKonrad Dybcio bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW], 0);
579b9c2ae6cSKrzysztof Kozlowski
580ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE0],
581ec63dcd3SKrzysztof Kozlowski BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT);
582ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE1],
583ec63dcd3SKrzysztof Kozlowski data->zone1_thres_count);
584ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE2],
585ec63dcd3SKrzysztof Kozlowski BWMON_THRESHOLD_COUNT_ZONE2_DEFAULT);
586ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE3],
587ec63dcd3SKrzysztof Kozlowski data->zone3_thres_count);
588ec63dcd3SKrzysztof Kozlowski
589ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE0],
590ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE0);
591ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE1],
592ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE1);
593ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE2],
594ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE2);
595ec63dcd3SKrzysztof Kozlowski regmap_field_write(bwmon->regs[F_ZONE_ACTIONS_ZONE3],
596ec63dcd3SKrzysztof Kozlowski BWMON_ZONE_ACTIONS_ZONE3);
597b9c2ae6cSKrzysztof Kozlowski
598b9c2ae6cSKrzysztof Kozlowski bwmon_clear_irq(bwmon);
599b9c2ae6cSKrzysztof Kozlowski bwmon_enable(bwmon, BWMON_IRQ_ENABLE_MASK);
600b9c2ae6cSKrzysztof Kozlowski }
601b9c2ae6cSKrzysztof Kozlowski
bwmon_intr(int irq,void * dev_id)602b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr(int irq, void *dev_id)
603b9c2ae6cSKrzysztof Kozlowski {
604b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = dev_id;
605b9c2ae6cSKrzysztof Kozlowski unsigned int status, max;
606b9c2ae6cSKrzysztof Kozlowski int zone;
607b9c2ae6cSKrzysztof Kozlowski
608ec63dcd3SKrzysztof Kozlowski if (regmap_field_read(bwmon->regs[F_IRQ_STATUS], &status))
609ec63dcd3SKrzysztof Kozlowski return IRQ_NONE;
610ec63dcd3SKrzysztof Kozlowski
611b9c2ae6cSKrzysztof Kozlowski status &= BWMON_IRQ_ENABLE_MASK;
612b9c2ae6cSKrzysztof Kozlowski if (!status) {
613b9c2ae6cSKrzysztof Kozlowski /*
614b9c2ae6cSKrzysztof Kozlowski * Only zone 1 and zone 3 interrupts are enabled but zone 2
615b9c2ae6cSKrzysztof Kozlowski * threshold could be hit and trigger interrupt even if not
616b9c2ae6cSKrzysztof Kozlowski * enabled.
617b9c2ae6cSKrzysztof Kozlowski * Such spurious interrupt might come with valuable max count or
618b9c2ae6cSKrzysztof Kozlowski * not, so solution would be to always check all
619b9c2ae6cSKrzysztof Kozlowski * BWMON_ZONE_MAX() registers to find the highest value.
620b9c2ae6cSKrzysztof Kozlowski * Such case is currently ignored.
621b9c2ae6cSKrzysztof Kozlowski */
622b9c2ae6cSKrzysztof Kozlowski return IRQ_NONE;
623b9c2ae6cSKrzysztof Kozlowski }
624b9c2ae6cSKrzysztof Kozlowski
625b9c2ae6cSKrzysztof Kozlowski bwmon_disable(bwmon);
626b9c2ae6cSKrzysztof Kozlowski
627ec63dcd3SKrzysztof Kozlowski zone = get_bitmask_order(status) - 1;
628b9c2ae6cSKrzysztof Kozlowski /*
629b9c2ae6cSKrzysztof Kozlowski * Zone max bytes count register returns count units within sampling
630b9c2ae6cSKrzysztof Kozlowski * window. Downstream kernel for BWMONv4 (called BWMON type 2 in
631b9c2ae6cSKrzysztof Kozlowski * downstream) always increments the max bytes count by one.
632b9c2ae6cSKrzysztof Kozlowski */
633ec63dcd3SKrzysztof Kozlowski if (regmap_field_read(bwmon->regs[F_ZONE0_MAX + zone], &max))
634ec63dcd3SKrzysztof Kozlowski return IRQ_NONE;
635ec63dcd3SKrzysztof Kozlowski
636ec63dcd3SKrzysztof Kozlowski max += 1;
637650db9faSKrzysztof Kozlowski max *= bwmon->data->count_unit_kb;
6381dd5246eSKrzysztof Kozlowski bwmon->target_kbps = mult_frac(max, MSEC_PER_SEC, bwmon->data->sample_ms);
639b9c2ae6cSKrzysztof Kozlowski
640b9c2ae6cSKrzysztof Kozlowski return IRQ_WAKE_THREAD;
641b9c2ae6cSKrzysztof Kozlowski }
642b9c2ae6cSKrzysztof Kozlowski
bwmon_intr_thread(int irq,void * dev_id)643b9c2ae6cSKrzysztof Kozlowski static irqreturn_t bwmon_intr_thread(int irq, void *dev_id)
644b9c2ae6cSKrzysztof Kozlowski {
645b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon = dev_id;
646b9c2ae6cSKrzysztof Kozlowski unsigned int irq_enable = 0;
647b9c2ae6cSKrzysztof Kozlowski struct dev_pm_opp *opp, *target_opp;
648b9c2ae6cSKrzysztof Kozlowski unsigned int bw_kbps, up_kbps, down_kbps;
649b9c2ae6cSKrzysztof Kozlowski
650b9c2ae6cSKrzysztof Kozlowski bw_kbps = bwmon->target_kbps;
651b9c2ae6cSKrzysztof Kozlowski
652b9c2ae6cSKrzysztof Kozlowski target_opp = dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_kbps, 0);
653b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(target_opp) && PTR_ERR(target_opp) == -ERANGE)
654b9c2ae6cSKrzysztof Kozlowski target_opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0);
655b9c2ae6cSKrzysztof Kozlowski
656b9c2ae6cSKrzysztof Kozlowski bwmon->target_kbps = bw_kbps;
657b9c2ae6cSKrzysztof Kozlowski
658b9c2ae6cSKrzysztof Kozlowski bw_kbps--;
659b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_floor(bwmon->dev, &bw_kbps, 0);
660b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp) && PTR_ERR(opp) == -ERANGE)
661b9c2ae6cSKrzysztof Kozlowski down_kbps = bwmon->target_kbps;
662b9c2ae6cSKrzysztof Kozlowski else
663b9c2ae6cSKrzysztof Kozlowski down_kbps = bw_kbps;
664b9c2ae6cSKrzysztof Kozlowski
665b9c2ae6cSKrzysztof Kozlowski up_kbps = bwmon->target_kbps + 1;
666b9c2ae6cSKrzysztof Kozlowski
667b9c2ae6cSKrzysztof Kozlowski if (bwmon->target_kbps >= bwmon->max_bw_kbps)
668ec63dcd3SKrzysztof Kozlowski irq_enable = BIT(1);
669b9c2ae6cSKrzysztof Kozlowski else if (bwmon->target_kbps <= bwmon->min_bw_kbps)
670ec63dcd3SKrzysztof Kozlowski irq_enable = BIT(3);
671b9c2ae6cSKrzysztof Kozlowski else
672b9c2ae6cSKrzysztof Kozlowski irq_enable = BWMON_IRQ_ENABLE_MASK;
673b9c2ae6cSKrzysztof Kozlowski
674ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH],
675ec63dcd3SKrzysztof Kozlowski up_kbps);
676ec63dcd3SKrzysztof Kozlowski bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED],
677ec63dcd3SKrzysztof Kozlowski down_kbps);
678956deab5SKrzysztof Kozlowski bwmon_clear_counters(bwmon, false);
679b9c2ae6cSKrzysztof Kozlowski bwmon_clear_irq(bwmon);
680b9c2ae6cSKrzysztof Kozlowski bwmon_enable(bwmon, irq_enable);
681b9c2ae6cSKrzysztof Kozlowski
682b9c2ae6cSKrzysztof Kozlowski if (bwmon->target_kbps == bwmon->current_kbps)
683b9c2ae6cSKrzysztof Kozlowski goto out;
684b9c2ae6cSKrzysztof Kozlowski
685b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_set_opp(bwmon->dev, target_opp);
686b9c2ae6cSKrzysztof Kozlowski bwmon->current_kbps = bwmon->target_kbps;
687b9c2ae6cSKrzysztof Kozlowski
688b9c2ae6cSKrzysztof Kozlowski out:
689b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_put(target_opp);
690b9c2ae6cSKrzysztof Kozlowski if (!IS_ERR(opp))
691b9c2ae6cSKrzysztof Kozlowski dev_pm_opp_put(opp);
692b9c2ae6cSKrzysztof Kozlowski
693b9c2ae6cSKrzysztof Kozlowski return IRQ_HANDLED;
694b9c2ae6cSKrzysztof Kozlowski }
695b9c2ae6cSKrzysztof Kozlowski
bwmon_init_regmap(struct platform_device * pdev,struct icc_bwmon * bwmon)696ec63dcd3SKrzysztof Kozlowski static int bwmon_init_regmap(struct platform_device *pdev,
697ec63dcd3SKrzysztof Kozlowski struct icc_bwmon *bwmon)
698ec63dcd3SKrzysztof Kozlowski {
699ec63dcd3SKrzysztof Kozlowski struct device *dev = &pdev->dev;
700ec63dcd3SKrzysztof Kozlowski void __iomem *base;
701ec63dcd3SKrzysztof Kozlowski struct regmap *map;
702b6e9fb7aSKonrad Dybcio int ret;
703ec63dcd3SKrzysztof Kozlowski
704b6e9fb7aSKonrad Dybcio /* Map the monitor base */
705ec63dcd3SKrzysztof Kozlowski base = devm_platform_ioremap_resource(pdev, 0);
706ec63dcd3SKrzysztof Kozlowski if (IS_ERR(base))
707ec63dcd3SKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(base),
708ec63dcd3SKrzysztof Kozlowski "failed to map bwmon registers\n");
709ec63dcd3SKrzysztof Kozlowski
710ec63dcd3SKrzysztof Kozlowski map = devm_regmap_init_mmio(dev, base, bwmon->data->regmap_cfg);
711ec63dcd3SKrzysztof Kozlowski if (IS_ERR(map))
712ec63dcd3SKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(map),
713ec63dcd3SKrzysztof Kozlowski "failed to initialize regmap\n");
714ec63dcd3SKrzysztof Kozlowski
715b6e9fb7aSKonrad Dybcio BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_global_reg_fields) != F_NUM_GLOBAL_FIELDS);
716ec63dcd3SKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(msm8998_bwmon_reg_fields) != F_NUM_FIELDS);
717b6e9fb7aSKonrad Dybcio BUILD_BUG_ON(ARRAY_SIZE(sdm845_cpu_bwmon_reg_fields) != F_NUM_FIELDS);
71814af4ce0SKrzysztof Kozlowski BUILD_BUG_ON(ARRAY_SIZE(sdm845_llcc_bwmon_reg_fields) != F_NUM_FIELDS);
7197eb89c17SJinpeng Cui
720b6e9fb7aSKonrad Dybcio ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->regs,
721ec63dcd3SKrzysztof Kozlowski bwmon->data->regmap_fields,
722ec63dcd3SKrzysztof Kozlowski F_NUM_FIELDS);
723b6e9fb7aSKonrad Dybcio if (ret)
724b6e9fb7aSKonrad Dybcio return ret;
725b6e9fb7aSKonrad Dybcio
726b6e9fb7aSKonrad Dybcio if (bwmon->data->global_regmap_cfg) {
727b6e9fb7aSKonrad Dybcio /* Map the global base, if separate */
728b6e9fb7aSKonrad Dybcio base = devm_platform_ioremap_resource(pdev, 1);
729b6e9fb7aSKonrad Dybcio if (IS_ERR(base))
730b6e9fb7aSKonrad Dybcio return dev_err_probe(dev, PTR_ERR(base),
731b6e9fb7aSKonrad Dybcio "failed to map bwmon global registers\n");
732b6e9fb7aSKonrad Dybcio
733b6e9fb7aSKonrad Dybcio map = devm_regmap_init_mmio(dev, base, bwmon->data->global_regmap_cfg);
734b6e9fb7aSKonrad Dybcio if (IS_ERR(map))
735b6e9fb7aSKonrad Dybcio return dev_err_probe(dev, PTR_ERR(map),
736b6e9fb7aSKonrad Dybcio "failed to initialize global regmap\n");
737b6e9fb7aSKonrad Dybcio
738b6e9fb7aSKonrad Dybcio ret = devm_regmap_field_bulk_alloc(dev, map, bwmon->global_regs,
739b6e9fb7aSKonrad Dybcio bwmon->data->global_regmap_fields,
740b6e9fb7aSKonrad Dybcio F_NUM_GLOBAL_FIELDS);
741b6e9fb7aSKonrad Dybcio }
742b6e9fb7aSKonrad Dybcio
743b6e9fb7aSKonrad Dybcio return ret;
744ec63dcd3SKrzysztof Kozlowski }
745ec63dcd3SKrzysztof Kozlowski
bwmon_probe(struct platform_device * pdev)746b9c2ae6cSKrzysztof Kozlowski static int bwmon_probe(struct platform_device *pdev)
747b9c2ae6cSKrzysztof Kozlowski {
748b9c2ae6cSKrzysztof Kozlowski struct device *dev = &pdev->dev;
749b9c2ae6cSKrzysztof Kozlowski struct dev_pm_opp *opp;
750b9c2ae6cSKrzysztof Kozlowski struct icc_bwmon *bwmon;
751b9c2ae6cSKrzysztof Kozlowski int ret;
752b9c2ae6cSKrzysztof Kozlowski
753b9c2ae6cSKrzysztof Kozlowski bwmon = devm_kzalloc(dev, sizeof(*bwmon), GFP_KERNEL);
754b9c2ae6cSKrzysztof Kozlowski if (!bwmon)
755b9c2ae6cSKrzysztof Kozlowski return -ENOMEM;
756b9c2ae6cSKrzysztof Kozlowski
7571dd5246eSKrzysztof Kozlowski bwmon->data = of_device_get_match_data(dev);
758b9c2ae6cSKrzysztof Kozlowski
759ec63dcd3SKrzysztof Kozlowski ret = bwmon_init_regmap(pdev, bwmon);
760ec63dcd3SKrzysztof Kozlowski if (ret)
761ec63dcd3SKrzysztof Kozlowski return ret;
762b9c2ae6cSKrzysztof Kozlowski
763b9c2ae6cSKrzysztof Kozlowski bwmon->irq = platform_get_irq(pdev, 0);
764947bb0d1SYang Li if (bwmon->irq < 0)
765b9c2ae6cSKrzysztof Kozlowski return bwmon->irq;
766b9c2ae6cSKrzysztof Kozlowski
767b9c2ae6cSKrzysztof Kozlowski ret = devm_pm_opp_of_add_table(dev);
768b9c2ae6cSKrzysztof Kozlowski if (ret)
769b9c2ae6cSKrzysztof Kozlowski return dev_err_probe(dev, ret, "failed to add OPP table\n");
770b9c2ae6cSKrzysztof Kozlowski
771b9c2ae6cSKrzysztof Kozlowski bwmon->max_bw_kbps = UINT_MAX;
772b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0);
773b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp))
7743530167cSKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(opp), "failed to find max peak bandwidth\n");
775*aad41f4cSSibi Sankar dev_pm_opp_put(opp);
776b9c2ae6cSKrzysztof Kozlowski
777b9c2ae6cSKrzysztof Kozlowski bwmon->min_bw_kbps = 0;
778b9c2ae6cSKrzysztof Kozlowski opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0);
779b9c2ae6cSKrzysztof Kozlowski if (IS_ERR(opp))
7803530167cSKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(opp), "failed to find min peak bandwidth\n");
781*aad41f4cSSibi Sankar dev_pm_opp_put(opp);
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
bwmon_remove(struct platform_device * pdev)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,
8091c8267cdSKonrad Dybcio .count_unit_kb = 1024,
810b9c2ae6cSKrzysztof Kozlowski .zone1_thres_count = 16,
811b9c2ae6cSKrzysztof Kozlowski .zone3_thres_count = 1,
812e6f34184SKrzysztof Kozlowski .quirks = BWMON_HAS_GLOBAL_IRQ,
813ec63dcd3SKrzysztof Kozlowski .regmap_fields = msm8998_bwmon_reg_fields,
814ec63dcd3SKrzysztof Kozlowski .regmap_cfg = &msm8998_bwmon_regmap_cfg,
815b6e9fb7aSKonrad Dybcio .global_regmap_fields = msm8998_bwmon_global_reg_fields,
816b6e9fb7aSKonrad Dybcio .global_regmap_cfg = &msm8998_bwmon_global_regmap_cfg,
817b6e9fb7aSKonrad Dybcio };
818b6e9fb7aSKonrad Dybcio
819b6e9fb7aSKonrad Dybcio static const struct icc_bwmon_data sdm845_cpu_bwmon_data = {
820b6e9fb7aSKonrad Dybcio .sample_ms = 4,
821b6e9fb7aSKonrad Dybcio .count_unit_kb = 64,
822b6e9fb7aSKonrad Dybcio .zone1_thres_count = 16,
823b6e9fb7aSKonrad Dybcio .zone3_thres_count = 1,
824b6e9fb7aSKonrad Dybcio .quirks = BWMON_HAS_GLOBAL_IRQ,
825b6e9fb7aSKonrad Dybcio .regmap_fields = sdm845_cpu_bwmon_reg_fields,
826b6e9fb7aSKonrad Dybcio .regmap_cfg = &sdm845_cpu_bwmon_regmap_cfg,
827b9c2ae6cSKrzysztof Kozlowski };
828b9c2ae6cSKrzysztof Kozlowski
82914af4ce0SKrzysztof Kozlowski static const struct icc_bwmon_data sdm845_llcc_bwmon_data = {
83014af4ce0SKrzysztof Kozlowski .sample_ms = 4,
83114af4ce0SKrzysztof Kozlowski .count_unit_kb = 1024,
83214af4ce0SKrzysztof Kozlowski .zone1_thres_count = 16,
83314af4ce0SKrzysztof Kozlowski .zone3_thres_count = 1,
83414af4ce0SKrzysztof Kozlowski .regmap_fields = sdm845_llcc_bwmon_reg_fields,
83514af4ce0SKrzysztof Kozlowski .regmap_cfg = &sdm845_llcc_bwmon_regmap_cfg,
83614af4ce0SKrzysztof Kozlowski };
83714af4ce0SKrzysztof Kozlowski
8381335fc5bSRajendra Nayak static const struct icc_bwmon_data sc7280_llcc_bwmon_data = {
8391335fc5bSRajendra Nayak .sample_ms = 4,
8401335fc5bSRajendra Nayak .count_unit_kb = 64,
8411335fc5bSRajendra Nayak .zone1_thres_count = 16,
8421335fc5bSRajendra Nayak .zone3_thres_count = 1,
843cdad59c2SRajendra Nayak .quirks = BWMON_NEEDS_FORCE_CLEAR,
8441335fc5bSRajendra Nayak .regmap_fields = sdm845_llcc_bwmon_reg_fields,
8451335fc5bSRajendra Nayak .regmap_cfg = &sdm845_llcc_bwmon_regmap_cfg,
8461335fc5bSRajendra Nayak };
8471335fc5bSRajendra Nayak
848b9c2ae6cSKrzysztof Kozlowski static const struct of_device_id bwmon_of_match[] = {
849b6e9fb7aSKonrad Dybcio /* BWMONv4, separate monitor and global register spaces */
850b6e9fb7aSKonrad Dybcio { .compatible = "qcom,msm8998-bwmon", .data = &msm8998_bwmon_data },
851b6e9fb7aSKonrad Dybcio /* BWMONv4, unified register space */
852b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sdm845-bwmon", .data = &sdm845_cpu_bwmon_data },
853b6e9fb7aSKonrad Dybcio /* BWMONv5 */
854b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sdm845-llcc-bwmon", .data = &sdm845_llcc_bwmon_data },
855b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sc7280-llcc-bwmon", .data = &sc7280_llcc_bwmon_data },
856b6e9fb7aSKonrad Dybcio
857b6e9fb7aSKonrad Dybcio /* Compatibles kept for legacy reasons */
858b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sc7280-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
859b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sc8280xp-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
860b6e9fb7aSKonrad Dybcio { .compatible = "qcom,sm8550-cpu-bwmon", .data = &sdm845_cpu_bwmon_data },
861b9c2ae6cSKrzysztof Kozlowski {}
862b9c2ae6cSKrzysztof Kozlowski };
863b9c2ae6cSKrzysztof Kozlowski MODULE_DEVICE_TABLE(of, bwmon_of_match);
864b9c2ae6cSKrzysztof Kozlowski
865b9c2ae6cSKrzysztof Kozlowski static struct platform_driver bwmon_driver = {
866b9c2ae6cSKrzysztof Kozlowski .probe = bwmon_probe,
867b9c2ae6cSKrzysztof Kozlowski .remove = bwmon_remove,
868b9c2ae6cSKrzysztof Kozlowski .driver = {
869b9c2ae6cSKrzysztof Kozlowski .name = "qcom-bwmon",
870b9c2ae6cSKrzysztof Kozlowski .of_match_table = bwmon_of_match,
871b9c2ae6cSKrzysztof Kozlowski },
872b9c2ae6cSKrzysztof Kozlowski };
873b9c2ae6cSKrzysztof Kozlowski module_platform_driver(bwmon_driver);
874b9c2ae6cSKrzysztof Kozlowski
875b9c2ae6cSKrzysztof Kozlowski MODULE_AUTHOR("Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>");
876b9c2ae6cSKrzysztof Kozlowski MODULE_DESCRIPTION("QCOM BWMON driver");
877b9c2ae6cSKrzysztof Kozlowski MODULE_LICENSE("GPL");
878