1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
7 #include <linux/bitmap.h>
8 #include <linux/bitops.h>
9 #include <linux/device.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/of_device.h>
15 #include <linux/regmap.h>
16 #include <linux/slab.h>
17 #include <linux/soc/qcom/llcc-qcom.h>
19 #define ACTIVATE BIT(0)
20 #define DEACTIVATE BIT(1)
21 #define ACT_CTRL_OPCODE_ACTIVATE BIT(0)
22 #define ACT_CTRL_OPCODE_DEACTIVATE BIT(1)
23 #define ACT_CTRL_ACT_TRIG BIT(0)
24 #define ACT_CTRL_OPCODE_SHIFT 0x01
25 #define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02
26 #define ATTR1_FIXED_SIZE_SHIFT 0x03
27 #define ATTR1_PRIORITY_SHIFT 0x04
28 #define ATTR1_MAX_CAP_SHIFT 0x10
29 #define ATTR0_RES_WAYS_MASK GENMASK(11, 0)
30 #define ATTR0_BONUS_WAYS_MASK GENMASK(27, 16)
31 #define ATTR0_BONUS_WAYS_SHIFT 0x10
32 #define LLCC_STATUS_READ_DELAY 100
34 #define CACHE_LINE_SIZE_SHIFT 6
36 #define LLCC_COMMON_STATUS0 0x0003000c
37 #define LLCC_LB_CNT_MASK GENMASK(31, 28)
38 #define LLCC_LB_CNT_SHIFT 28
40 #define MAX_CAP_TO_BYTES(n) (n * SZ_1K)
41 #define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K)
42 #define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K)
43 #define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n)
44 #define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n)
46 #define BANK_OFFSET_STRIDE 0x80000
48 static struct llcc_drv_data
*drv_data
;
50 static const struct regmap_config llcc_regmap_config
= {
58 * llcc_slice_getd - get llcc slice descriptor
59 * @uid: usecase_id for the client
61 * A pointer to llcc slice descriptor will be returned on success and
62 * and error pointer is returned on failure
64 struct llcc_slice_desc
*llcc_slice_getd(u32 uid
)
66 const struct llcc_slice_config
*cfg
;
67 struct llcc_slice_desc
*desc
;
71 sz
= drv_data
->cfg_size
;
73 for (count
= 0; cfg
&& count
< sz
; count
++, cfg
++)
74 if (cfg
->usecase_id
== uid
)
77 if (count
== sz
|| !cfg
)
78 return ERR_PTR(-ENODEV
);
80 desc
= kzalloc(sizeof(*desc
), GFP_KERNEL
);
82 return ERR_PTR(-ENOMEM
);
84 desc
->slice_id
= cfg
->slice_id
;
85 desc
->slice_size
= cfg
->max_cap
;
89 EXPORT_SYMBOL_GPL(llcc_slice_getd
);
92 * llcc_slice_putd - llcc slice descritpor
93 * @desc: Pointer to llcc slice descriptor
95 void llcc_slice_putd(struct llcc_slice_desc
*desc
)
99 EXPORT_SYMBOL_GPL(llcc_slice_putd
);
101 static int llcc_update_act_ctrl(u32 sid
,
102 u32 act_ctrl_reg_val
, u32 status
)
109 act_ctrl_reg
= drv_data
->bcast_off
+ LLCC_TRP_ACT_CTRLn(sid
);
110 status_reg
= drv_data
->bcast_off
+ LLCC_TRP_STATUSn(sid
);
112 /* Set the ACTIVE trigger */
113 act_ctrl_reg_val
|= ACT_CTRL_ACT_TRIG
;
114 ret
= regmap_write(drv_data
->regmap
, act_ctrl_reg
, act_ctrl_reg_val
);
118 /* Clear the ACTIVE trigger */
119 act_ctrl_reg_val
&= ~ACT_CTRL_ACT_TRIG
;
120 ret
= regmap_write(drv_data
->regmap
, act_ctrl_reg
, act_ctrl_reg_val
);
124 ret
= regmap_read_poll_timeout(drv_data
->regmap
, status_reg
,
125 slice_status
, !(slice_status
& status
),
126 0, LLCC_STATUS_READ_DELAY
);
131 * llcc_slice_activate - Activate the llcc slice
132 * @desc: Pointer to llcc slice descriptor
134 * A value of zero will be returned on success and a negative errno will
135 * be returned in error cases
137 int llcc_slice_activate(struct llcc_slice_desc
*desc
)
142 mutex_lock(&drv_data
->lock
);
143 if (test_bit(desc
->slice_id
, drv_data
->bitmap
)) {
144 mutex_unlock(&drv_data
->lock
);
148 act_ctrl_val
= ACT_CTRL_OPCODE_ACTIVATE
<< ACT_CTRL_OPCODE_SHIFT
;
150 ret
= llcc_update_act_ctrl(desc
->slice_id
, act_ctrl_val
,
153 mutex_unlock(&drv_data
->lock
);
157 __set_bit(desc
->slice_id
, drv_data
->bitmap
);
158 mutex_unlock(&drv_data
->lock
);
162 EXPORT_SYMBOL_GPL(llcc_slice_activate
);
165 * llcc_slice_deactivate - Deactivate the llcc slice
166 * @desc: Pointer to llcc slice descriptor
168 * A value of zero will be returned on success and a negative errno will
169 * be returned in error cases
171 int llcc_slice_deactivate(struct llcc_slice_desc
*desc
)
176 mutex_lock(&drv_data
->lock
);
177 if (!test_bit(desc
->slice_id
, drv_data
->bitmap
)) {
178 mutex_unlock(&drv_data
->lock
);
181 act_ctrl_val
= ACT_CTRL_OPCODE_DEACTIVATE
<< ACT_CTRL_OPCODE_SHIFT
;
183 ret
= llcc_update_act_ctrl(desc
->slice_id
, act_ctrl_val
,
186 mutex_unlock(&drv_data
->lock
);
190 __clear_bit(desc
->slice_id
, drv_data
->bitmap
);
191 mutex_unlock(&drv_data
->lock
);
195 EXPORT_SYMBOL_GPL(llcc_slice_deactivate
);
198 * llcc_get_slice_id - return the slice id
199 * @desc: Pointer to llcc slice descriptor
201 int llcc_get_slice_id(struct llcc_slice_desc
*desc
)
203 return desc
->slice_id
;
205 EXPORT_SYMBOL_GPL(llcc_get_slice_id
);
208 * llcc_get_slice_size - return the slice id
209 * @desc: Pointer to llcc slice descriptor
211 size_t llcc_get_slice_size(struct llcc_slice_desc
*desc
)
213 return desc
->slice_size
;
215 EXPORT_SYMBOL_GPL(llcc_get_slice_size
);
217 static int qcom_llcc_cfg_program(struct platform_device
*pdev
)
224 u32 max_cap_cacheline
;
227 const struct llcc_slice_config
*llcc_table
;
228 struct llcc_slice_desc desc
;
229 u32 bcast_off
= drv_data
->bcast_off
;
231 sz
= drv_data
->cfg_size
;
232 llcc_table
= drv_data
->cfg
;
234 for (i
= 0; i
< sz
; i
++) {
235 attr1_cfg
= bcast_off
+
236 LLCC_TRP_ATTR1_CFGn(llcc_table
[i
].slice_id
);
237 attr0_cfg
= bcast_off
+
238 LLCC_TRP_ATTR0_CFGn(llcc_table
[i
].slice_id
);
240 attr1_val
= llcc_table
[i
].cache_mode
;
241 attr1_val
|= llcc_table
[i
].probe_target_ways
<<
242 ATTR1_PROBE_TARGET_WAYS_SHIFT
;
243 attr1_val
|= llcc_table
[i
].fixed_size
<<
244 ATTR1_FIXED_SIZE_SHIFT
;
245 attr1_val
|= llcc_table
[i
].priority
<<
246 ATTR1_PRIORITY_SHIFT
;
248 max_cap_cacheline
= MAX_CAP_TO_BYTES(llcc_table
[i
].max_cap
);
250 /* LLCC instances can vary for each target.
251 * The SW writes to broadcast register which gets propagated
252 * to each llcc instace (llcc0,.. llccN).
253 * Since the size of the memory is divided equally amongst the
254 * llcc instances, we need to configure the max cap accordingly.
256 max_cap_cacheline
= max_cap_cacheline
/ drv_data
->num_banks
;
257 max_cap_cacheline
>>= CACHE_LINE_SIZE_SHIFT
;
258 attr1_val
|= max_cap_cacheline
<< ATTR1_MAX_CAP_SHIFT
;
260 attr0_val
= llcc_table
[i
].res_ways
& ATTR0_RES_WAYS_MASK
;
261 attr0_val
|= llcc_table
[i
].bonus_ways
<< ATTR0_BONUS_WAYS_SHIFT
;
263 ret
= regmap_write(drv_data
->regmap
, attr1_cfg
, attr1_val
);
266 ret
= regmap_write(drv_data
->regmap
, attr0_cfg
, attr0_val
);
269 if (llcc_table
[i
].activate_on_init
) {
270 desc
.slice_id
= llcc_table
[i
].slice_id
;
271 ret
= llcc_slice_activate(&desc
);
277 int qcom_llcc_probe(struct platform_device
*pdev
,
278 const struct llcc_slice_config
*llcc_cfg
, u32 sz
)
281 struct device
*dev
= &pdev
->dev
;
282 struct resource
*res
;
286 drv_data
= devm_kzalloc(dev
, sizeof(*drv_data
), GFP_KERNEL
);
290 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
291 base
= devm_ioremap_resource(&pdev
->dev
, res
);
293 return PTR_ERR(base
);
295 drv_data
->regmap
= devm_regmap_init_mmio(dev
, base
,
296 &llcc_regmap_config
);
297 if (IS_ERR(drv_data
->regmap
))
298 return PTR_ERR(drv_data
->regmap
);
300 ret
= regmap_read(drv_data
->regmap
, LLCC_COMMON_STATUS0
,
305 num_banks
&= LLCC_LB_CNT_MASK
;
306 num_banks
>>= LLCC_LB_CNT_SHIFT
;
307 drv_data
->num_banks
= num_banks
;
309 for (i
= 0; i
< sz
; i
++)
310 if (llcc_cfg
[i
].slice_id
> drv_data
->max_slices
)
311 drv_data
->max_slices
= llcc_cfg
[i
].slice_id
;
313 drv_data
->offsets
= devm_kcalloc(dev
, num_banks
, sizeof(u32
),
315 if (!drv_data
->offsets
)
318 for (i
= 0; i
< num_banks
; i
++)
319 drv_data
->offsets
[i
] = i
* BANK_OFFSET_STRIDE
;
321 drv_data
->bcast_off
= num_banks
* BANK_OFFSET_STRIDE
;
323 drv_data
->bitmap
= devm_kcalloc(dev
,
324 BITS_TO_LONGS(drv_data
->max_slices
), sizeof(unsigned long),
326 if (!drv_data
->bitmap
)
329 drv_data
->cfg
= llcc_cfg
;
330 drv_data
->cfg_size
= sz
;
331 mutex_init(&drv_data
->lock
);
332 platform_set_drvdata(pdev
, drv_data
);
334 return qcom_llcc_cfg_program(pdev
);
336 EXPORT_SYMBOL_GPL(qcom_llcc_probe
);
338 MODULE_LICENSE("GPL v2");