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