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/sizes.h>
17 #include <linux/slab.h>
18 #include <linux/soc/qcom/llcc-qcom.h>
20 #define ACTIVATE BIT(0)
21 #define DEACTIVATE BIT(1)
22 #define ACT_CTRL_OPCODE_ACTIVATE BIT(0)
23 #define ACT_CTRL_OPCODE_DEACTIVATE BIT(1)
24 #define ACT_CTRL_ACT_TRIG BIT(0)
25 #define ACT_CTRL_OPCODE_SHIFT 0x01
26 #define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02
27 #define ATTR1_FIXED_SIZE_SHIFT 0x03
28 #define ATTR1_PRIORITY_SHIFT 0x04
29 #define ATTR1_MAX_CAP_SHIFT 0x10
30 #define ATTR0_RES_WAYS_MASK GENMASK(11, 0)
31 #define ATTR0_BONUS_WAYS_MASK GENMASK(27, 16)
32 #define ATTR0_BONUS_WAYS_SHIFT 0x10
33 #define LLCC_STATUS_READ_DELAY 100
35 #define CACHE_LINE_SIZE_SHIFT 6
37 #define LLCC_COMMON_STATUS0 0x0003000c
38 #define LLCC_LB_CNT_MASK GENMASK(31, 28)
39 #define LLCC_LB_CNT_SHIFT 28
41 #define MAX_CAP_TO_BYTES(n) (n * SZ_1K)
42 #define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K)
43 #define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K)
44 #define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n)
45 #define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n)
47 #define BANK_OFFSET_STRIDE 0x80000
49 static struct llcc_drv_data
*drv_data
;
51 static const struct regmap_config llcc_regmap_config
= {
59 * llcc_slice_getd - get llcc slice descriptor
60 * @uid: usecase_id for the client
62 * A pointer to llcc slice descriptor will be returned on success and
63 * and error pointer is returned on failure
65 struct llcc_slice_desc
*llcc_slice_getd(u32 uid
)
67 const struct llcc_slice_config
*cfg
;
68 struct llcc_slice_desc
*desc
;
72 sz
= drv_data
->cfg_size
;
74 for (count
= 0; cfg
&& count
< sz
; count
++, cfg
++)
75 if (cfg
->usecase_id
== uid
)
78 if (count
== sz
|| !cfg
)
79 return ERR_PTR(-ENODEV
);
81 desc
= kzalloc(sizeof(*desc
), GFP_KERNEL
);
83 return ERR_PTR(-ENOMEM
);
85 desc
->slice_id
= cfg
->slice_id
;
86 desc
->slice_size
= cfg
->max_cap
;
90 EXPORT_SYMBOL_GPL(llcc_slice_getd
);
93 * llcc_slice_putd - llcc slice descritpor
94 * @desc: Pointer to llcc slice descriptor
96 void llcc_slice_putd(struct llcc_slice_desc
*desc
)
100 EXPORT_SYMBOL_GPL(llcc_slice_putd
);
102 static int llcc_update_act_ctrl(u32 sid
,
103 u32 act_ctrl_reg_val
, u32 status
)
110 act_ctrl_reg
= LLCC_TRP_ACT_CTRLn(sid
);
111 status_reg
= LLCC_TRP_STATUSn(sid
);
113 /* Set the ACTIVE trigger */
114 act_ctrl_reg_val
|= ACT_CTRL_ACT_TRIG
;
115 ret
= regmap_write(drv_data
->bcast_regmap
, act_ctrl_reg
,
120 /* Clear the ACTIVE trigger */
121 act_ctrl_reg_val
&= ~ACT_CTRL_ACT_TRIG
;
122 ret
= regmap_write(drv_data
->bcast_regmap
, act_ctrl_reg
,
127 ret
= regmap_read_poll_timeout(drv_data
->bcast_regmap
, status_reg
,
128 slice_status
, !(slice_status
& status
),
129 0, LLCC_STATUS_READ_DELAY
);
134 * llcc_slice_activate - Activate the llcc slice
135 * @desc: Pointer to llcc slice descriptor
137 * A value of zero will be returned on success and a negative errno will
138 * be returned in error cases
140 int llcc_slice_activate(struct llcc_slice_desc
*desc
)
145 mutex_lock(&drv_data
->lock
);
146 if (test_bit(desc
->slice_id
, drv_data
->bitmap
)) {
147 mutex_unlock(&drv_data
->lock
);
151 act_ctrl_val
= ACT_CTRL_OPCODE_ACTIVATE
<< ACT_CTRL_OPCODE_SHIFT
;
153 ret
= llcc_update_act_ctrl(desc
->slice_id
, act_ctrl_val
,
156 mutex_unlock(&drv_data
->lock
);
160 __set_bit(desc
->slice_id
, drv_data
->bitmap
);
161 mutex_unlock(&drv_data
->lock
);
165 EXPORT_SYMBOL_GPL(llcc_slice_activate
);
168 * llcc_slice_deactivate - Deactivate the llcc slice
169 * @desc: Pointer to llcc slice descriptor
171 * A value of zero will be returned on success and a negative errno will
172 * be returned in error cases
174 int llcc_slice_deactivate(struct llcc_slice_desc
*desc
)
179 mutex_lock(&drv_data
->lock
);
180 if (!test_bit(desc
->slice_id
, drv_data
->bitmap
)) {
181 mutex_unlock(&drv_data
->lock
);
184 act_ctrl_val
= ACT_CTRL_OPCODE_DEACTIVATE
<< ACT_CTRL_OPCODE_SHIFT
;
186 ret
= llcc_update_act_ctrl(desc
->slice_id
, act_ctrl_val
,
189 mutex_unlock(&drv_data
->lock
);
193 __clear_bit(desc
->slice_id
, drv_data
->bitmap
);
194 mutex_unlock(&drv_data
->lock
);
198 EXPORT_SYMBOL_GPL(llcc_slice_deactivate
);
201 * llcc_get_slice_id - return the slice id
202 * @desc: Pointer to llcc slice descriptor
204 int llcc_get_slice_id(struct llcc_slice_desc
*desc
)
206 return desc
->slice_id
;
208 EXPORT_SYMBOL_GPL(llcc_get_slice_id
);
211 * llcc_get_slice_size - return the slice id
212 * @desc: Pointer to llcc slice descriptor
214 size_t llcc_get_slice_size(struct llcc_slice_desc
*desc
)
216 return desc
->slice_size
;
218 EXPORT_SYMBOL_GPL(llcc_get_slice_size
);
220 static int qcom_llcc_cfg_program(struct platform_device
*pdev
)
227 u32 max_cap_cacheline
;
230 const struct llcc_slice_config
*llcc_table
;
231 struct llcc_slice_desc desc
;
233 sz
= drv_data
->cfg_size
;
234 llcc_table
= drv_data
->cfg
;
236 for (i
= 0; i
< sz
; i
++) {
237 attr1_cfg
= LLCC_TRP_ATTR1_CFGn(llcc_table
[i
].slice_id
);
238 attr0_cfg
= 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
->bcast_regmap
, attr1_cfg
,
267 ret
= regmap_write(drv_data
->bcast_regmap
, attr0_cfg
,
271 if (llcc_table
[i
].activate_on_init
) {
272 desc
.slice_id
= llcc_table
[i
].slice_id
;
273 ret
= llcc_slice_activate(&desc
);
279 int qcom_llcc_probe(struct platform_device
*pdev
,
280 const struct llcc_slice_config
*llcc_cfg
, u32 sz
)
283 struct device
*dev
= &pdev
->dev
;
284 struct resource
*llcc_banks_res
, *llcc_bcast_res
;
285 void __iomem
*llcc_banks_base
, *llcc_bcast_base
;
287 struct platform_device
*llcc_edac
;
289 drv_data
= devm_kzalloc(dev
, sizeof(*drv_data
), GFP_KERNEL
);
293 llcc_banks_res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
,
295 llcc_banks_base
= devm_ioremap_resource(&pdev
->dev
, llcc_banks_res
);
296 if (IS_ERR(llcc_banks_base
))
297 return PTR_ERR(llcc_banks_base
);
299 drv_data
->regmap
= devm_regmap_init_mmio(dev
, llcc_banks_base
,
300 &llcc_regmap_config
);
301 if (IS_ERR(drv_data
->regmap
))
302 return PTR_ERR(drv_data
->regmap
);
304 llcc_bcast_res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
,
305 "llcc_broadcast_base");
306 llcc_bcast_base
= devm_ioremap_resource(&pdev
->dev
, llcc_bcast_res
);
307 if (IS_ERR(llcc_bcast_base
))
308 return PTR_ERR(llcc_bcast_base
);
310 drv_data
->bcast_regmap
= devm_regmap_init_mmio(dev
, llcc_bcast_base
,
311 &llcc_regmap_config
);
312 if (IS_ERR(drv_data
->bcast_regmap
))
313 return PTR_ERR(drv_data
->bcast_regmap
);
315 ret
= regmap_read(drv_data
->regmap
, LLCC_COMMON_STATUS0
,
320 num_banks
&= LLCC_LB_CNT_MASK
;
321 num_banks
>>= LLCC_LB_CNT_SHIFT
;
322 drv_data
->num_banks
= num_banks
;
324 for (i
= 0; i
< sz
; i
++)
325 if (llcc_cfg
[i
].slice_id
> drv_data
->max_slices
)
326 drv_data
->max_slices
= llcc_cfg
[i
].slice_id
;
328 drv_data
->offsets
= devm_kcalloc(dev
, num_banks
, sizeof(u32
),
330 if (!drv_data
->offsets
)
333 for (i
= 0; i
< num_banks
; i
++)
334 drv_data
->offsets
[i
] = i
* BANK_OFFSET_STRIDE
;
336 drv_data
->bitmap
= devm_kcalloc(dev
,
337 BITS_TO_LONGS(drv_data
->max_slices
), sizeof(unsigned long),
339 if (!drv_data
->bitmap
)
342 drv_data
->cfg
= llcc_cfg
;
343 drv_data
->cfg_size
= sz
;
344 mutex_init(&drv_data
->lock
);
345 platform_set_drvdata(pdev
, drv_data
);
347 ret
= qcom_llcc_cfg_program(pdev
);
351 drv_data
->ecc_irq
= platform_get_irq(pdev
, 0);
352 if (drv_data
->ecc_irq
>= 0) {
353 llcc_edac
= platform_device_register_data(&pdev
->dev
,
354 "qcom_llcc_edac", -1, drv_data
,
356 if (IS_ERR(llcc_edac
))
357 dev_err(dev
, "Failed to register llcc edac driver\n");
362 EXPORT_SYMBOL_GPL(qcom_llcc_probe
);
364 MODULE_LICENSE("GPL v2");