Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers: soc: Add LLCC driver

LLCC (Last Level Cache Controller) provides additional cache memory
in the system. LLCC is partitioned into multiple slices and each
slice gets its own priority, size, ID and other config parameters.
LLCC driver programs these parameters for each slice. Clients that
are assigned to use LLCC need to get information such size & ID of the
slice they get and activate or deactivate the slice as needed. LLCC driver
provides API for the clients to perform these operations.

Signed-off-by: Channagoud Kadabi <ckadabi@codeaurora.org>
Signed-off-by: Rishabh Bhatnagar <rishabhb@codeaurora.org>
Reviewed-by: Evan Green <evgreen@chromium.org>
Reviewed-by: Rob Herring <robh@kernel.org>
Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Signed-off-by: Andy Gross <andy.gross@linaro.org>

authored by

Rishabh Bhatnagar and committed by
Andy Gross
a3134fb0 7e5700ae

+628
+17
drivers/soc/qcom/Kconfig
··· 39 39 functions for connecting the underlying serial UART, SPI, and I2C 40 40 devices to the output pins. 41 41 42 + config QCOM_LLCC 43 + tristate "Qualcomm Technologies, Inc. LLCC driver" 44 + depends on ARCH_QCOM 45 + help 46 + Qualcomm Technologies, Inc. platform specific 47 + Last Level Cache Controller(LLCC) driver. This provides interfaces 48 + to clients that use the LLCC. Say yes here to enable LLCC slice 49 + driver. 50 + 51 + config QCOM_SDM845_LLCC 52 + tristate "Qualcomm Technologies, Inc. SDM845 LLCC driver" 53 + depends on QCOM_LLCC 54 + help 55 + Say yes here to enable the LLCC driver for SDM845. This provides 56 + data required to configure LLCC so that clients can start using the 57 + LLCC slices. 58 + 42 59 config QCOM_MDT_LOADER 43 60 tristate 44 61 select QCOM_SCM
+2
drivers/soc/qcom/Makefile
··· 15 15 obj-$(CONFIG_QCOM_SMSM) += smsm.o 16 16 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o 17 17 obj-$(CONFIG_QCOM_APR) += apr.o 18 + obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o 19 + obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
+94
drivers/soc/qcom/llcc-sdm845.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. 4 + * 5 + */ 6 + 7 + #include <linux/kernel.h> 8 + #include <linux/module.h> 9 + #include <linux/of.h> 10 + #include <linux/of_device.h> 11 + #include <linux/soc/qcom/llcc-qcom.h> 12 + 13 + /* 14 + * SCT(System Cache Table) entry contains of the following members: 15 + * usecase_id: Unique id for the client's use case 16 + * slice_id: llcc slice id for each client 17 + * max_cap: The maximum capacity of the cache slice provided in KB 18 + * priority: Priority of the client used to select victim line for replacement 19 + * fixed_size: Boolean indicating if the slice has a fixed capacity 20 + * bonus_ways: Bonus ways are additional ways to be used for any slice, 21 + * if client ends up using more than reserved cache ways. Bonus 22 + * ways are allocated only if they are not reserved for some 23 + * other client. 24 + * res_ways: Reserved ways for the cache slice, the reserved ways cannot 25 + * be used by any other client than the one its assigned to. 26 + * cache_mode: Each slice operates as a cache, this controls the mode of the 27 + * slice: normal or TCM(Tightly Coupled Memory) 28 + * probe_target_ways: Determines what ways to probe for access hit. When 29 + * configured to 1 only bonus and reserved ways are probed. 30 + * When configured to 0 all ways in llcc are probed. 31 + * dis_cap_alloc: Disable capacity based allocation for a client 32 + * retain_on_pc: If this bit is set and client has maintained active vote 33 + * then the ways assigned to this client are not flushed on power 34 + * collapse. 35 + * activate_on_init: Activate the slice immediately after the SCT is programmed 36 + */ 37 + #define SCT_ENTRY(uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \ 38 + { \ 39 + .usecase_id = uid, \ 40 + .slice_id = sid, \ 41 + .max_cap = mc, \ 42 + .priority = p, \ 43 + .fixed_size = fs, \ 44 + .bonus_ways = bway, \ 45 + .res_ways = rway, \ 46 + .cache_mode = cmod, \ 47 + .probe_target_ways = ptw, \ 48 + .dis_cap_alloc = dca, \ 49 + .retain_on_pc = rp, \ 50 + .activate_on_init = a, \ 51 + } 52 + 53 + static struct llcc_slice_config sdm845_data[] = { 54 + SCT_ENTRY(LLCC_CPUSS, 1, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 1), 55 + SCT_ENTRY(LLCC_VIDSC0, 2, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0), 56 + SCT_ENTRY(LLCC_VIDSC1, 3, 512, 2, 1, 0x0, 0x0f0, 0, 0, 1, 1, 0), 57 + SCT_ENTRY(LLCC_ROTATOR, 4, 563, 2, 1, 0x0, 0x00e, 2, 0, 1, 1, 0), 58 + SCT_ENTRY(LLCC_VOICE, 5, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 59 + SCT_ENTRY(LLCC_AUDIO, 6, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 60 + SCT_ENTRY(LLCC_MDMHPGRW, 7, 1024, 2, 0, 0xfc, 0xf00, 0, 0, 1, 1, 0), 61 + SCT_ENTRY(LLCC_MDM, 8, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 62 + SCT_ENTRY(LLCC_CMPT, 10, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 63 + SCT_ENTRY(LLCC_GPUHTW, 11, 512, 1, 1, 0xc, 0x0, 0, 0, 1, 1, 0), 64 + SCT_ENTRY(LLCC_GPU, 12, 2304, 1, 0, 0xff0, 0x2, 0, 0, 1, 1, 0), 65 + SCT_ENTRY(LLCC_MMUHWT, 13, 256, 2, 0, 0x0, 0x1, 0, 0, 1, 0, 1), 66 + SCT_ENTRY(LLCC_CMPTDMA, 15, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 67 + SCT_ENTRY(LLCC_DISP, 16, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 68 + SCT_ENTRY(LLCC_VIDFW, 17, 2816, 1, 0, 0xffc, 0x2, 0, 0, 1, 1, 0), 69 + SCT_ENTRY(LLCC_MDMHPFX, 20, 1024, 2, 1, 0x0, 0xf00, 0, 0, 1, 1, 0), 70 + SCT_ENTRY(LLCC_MDMPNG, 21, 1024, 0, 1, 0x1e, 0x0, 0, 0, 1, 1, 0), 71 + SCT_ENTRY(LLCC_AUDHW, 22, 1024, 1, 1, 0xffc, 0x2, 0, 0, 1, 1, 0), 72 + }; 73 + 74 + static int sdm845_qcom_llcc_probe(struct platform_device *pdev) 75 + { 76 + return qcom_llcc_probe(pdev, sdm845_data, ARRAY_SIZE(sdm845_data)); 77 + } 78 + 79 + static const struct of_device_id sdm845_qcom_llcc_of_match[] = { 80 + { .compatible = "qcom,sdm845-llcc", }, 81 + { } 82 + }; 83 + 84 + static struct platform_driver sdm845_qcom_llcc_driver = { 85 + .driver = { 86 + .name = "sdm845-llcc", 87 + .of_match_table = sdm845_qcom_llcc_of_match, 88 + }, 89 + .probe = sdm845_qcom_llcc_probe, 90 + }; 91 + module_platform_driver(sdm845_qcom_llcc_driver); 92 + 93 + MODULE_DESCRIPTION("QCOM sdm845 LLCC driver"); 94 + MODULE_LICENSE("GPL v2");
+335
drivers/soc/qcom/llcc-slice.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. 4 + * 5 + */ 6 + 7 + #include <linux/bitmap.h> 8 + #include <linux/bitops.h> 9 + #include <linux/device.h> 10 + #include <linux/io.h> 11 + #include <linux/kernel.h> 12 + #include <linux/mutex.h> 13 + #include <linux/of_device.h> 14 + #include <linux/regmap.h> 15 + #include <linux/slab.h> 16 + #include <linux/soc/qcom/llcc-qcom.h> 17 + 18 + #define ACTIVATE BIT(0) 19 + #define DEACTIVATE BIT(1) 20 + #define ACT_CTRL_OPCODE_ACTIVATE BIT(0) 21 + #define ACT_CTRL_OPCODE_DEACTIVATE BIT(1) 22 + #define ACT_CTRL_ACT_TRIG BIT(0) 23 + #define ACT_CTRL_OPCODE_SHIFT 0x01 24 + #define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02 25 + #define ATTR1_FIXED_SIZE_SHIFT 0x03 26 + #define ATTR1_PRIORITY_SHIFT 0x04 27 + #define ATTR1_MAX_CAP_SHIFT 0x10 28 + #define ATTR0_RES_WAYS_MASK GENMASK(11, 0) 29 + #define ATTR0_BONUS_WAYS_MASK GENMASK(27, 16) 30 + #define ATTR0_BONUS_WAYS_SHIFT 0x10 31 + #define LLCC_STATUS_READ_DELAY 100 32 + 33 + #define CACHE_LINE_SIZE_SHIFT 6 34 + 35 + #define LLCC_COMMON_STATUS0 0x0003000c 36 + #define LLCC_LB_CNT_MASK GENMASK(31, 28) 37 + #define LLCC_LB_CNT_SHIFT 28 38 + 39 + #define MAX_CAP_TO_BYTES(n) (n * SZ_1K) 40 + #define LLCC_TRP_ACT_CTRLn(n) (n * SZ_4K) 41 + #define LLCC_TRP_STATUSn(n) (4 + n * SZ_4K) 42 + #define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n) 43 + #define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n) 44 + 45 + #define BANK_OFFSET_STRIDE 0x80000 46 + 47 + static struct llcc_drv_data *drv_data; 48 + 49 + static const struct regmap_config llcc_regmap_config = { 50 + .reg_bits = 32, 51 + .reg_stride = 4, 52 + .val_bits = 32, 53 + .fast_io = true, 54 + }; 55 + 56 + /** 57 + * llcc_slice_getd - get llcc slice descriptor 58 + * @uid: usecase_id for the client 59 + * 60 + * A pointer to llcc slice descriptor will be returned on success and 61 + * and error pointer is returned on failure 62 + */ 63 + struct llcc_slice_desc *llcc_slice_getd(u32 uid) 64 + { 65 + const struct llcc_slice_config *cfg; 66 + struct llcc_slice_desc *desc; 67 + u32 sz, count; 68 + 69 + cfg = drv_data->cfg; 70 + sz = drv_data->cfg_size; 71 + 72 + for (count = 0; cfg && count < sz; count++, cfg++) 73 + if (cfg->usecase_id == uid) 74 + break; 75 + 76 + if (count == sz || !cfg) 77 + return ERR_PTR(-ENODEV); 78 + 79 + desc = kzalloc(sizeof(*desc), GFP_KERNEL); 80 + if (!desc) 81 + return ERR_PTR(-ENOMEM); 82 + 83 + desc->slice_id = cfg->slice_id; 84 + desc->slice_size = cfg->max_cap; 85 + 86 + return desc; 87 + } 88 + EXPORT_SYMBOL_GPL(llcc_slice_getd); 89 + 90 + /** 91 + * llcc_slice_putd - llcc slice descritpor 92 + * @desc: Pointer to llcc slice descriptor 93 + */ 94 + void llcc_slice_putd(struct llcc_slice_desc *desc) 95 + { 96 + kfree(desc); 97 + } 98 + EXPORT_SYMBOL_GPL(llcc_slice_putd); 99 + 100 + static int llcc_update_act_ctrl(u32 sid, 101 + u32 act_ctrl_reg_val, u32 status) 102 + { 103 + u32 act_ctrl_reg; 104 + u32 status_reg; 105 + u32 slice_status; 106 + int ret; 107 + 108 + act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid); 109 + status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid); 110 + 111 + /* Set the ACTIVE trigger */ 112 + act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG; 113 + ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); 114 + if (ret) 115 + return ret; 116 + 117 + /* Clear the ACTIVE trigger */ 118 + act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG; 119 + ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); 120 + if (ret) 121 + return ret; 122 + 123 + ret = regmap_read_poll_timeout(drv_data->regmap, status_reg, 124 + slice_status, !(slice_status & status), 125 + 0, LLCC_STATUS_READ_DELAY); 126 + return ret; 127 + } 128 + 129 + /** 130 + * llcc_slice_activate - Activate the llcc slice 131 + * @desc: Pointer to llcc slice descriptor 132 + * 133 + * A value of zero will be returned on success and a negative errno will 134 + * be returned in error cases 135 + */ 136 + int llcc_slice_activate(struct llcc_slice_desc *desc) 137 + { 138 + int ret; 139 + u32 act_ctrl_val; 140 + 141 + mutex_lock(&drv_data->lock); 142 + if (test_bit(desc->slice_id, drv_data->bitmap)) { 143 + mutex_unlock(&drv_data->lock); 144 + return 0; 145 + } 146 + 147 + act_ctrl_val = ACT_CTRL_OPCODE_ACTIVATE << ACT_CTRL_OPCODE_SHIFT; 148 + 149 + ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val, 150 + DEACTIVATE); 151 + if (ret) { 152 + mutex_unlock(&drv_data->lock); 153 + return ret; 154 + } 155 + 156 + __set_bit(desc->slice_id, drv_data->bitmap); 157 + mutex_unlock(&drv_data->lock); 158 + 159 + return ret; 160 + } 161 + EXPORT_SYMBOL_GPL(llcc_slice_activate); 162 + 163 + /** 164 + * llcc_slice_deactivate - Deactivate the llcc slice 165 + * @desc: Pointer to llcc slice descriptor 166 + * 167 + * A value of zero will be returned on success and a negative errno will 168 + * be returned in error cases 169 + */ 170 + int llcc_slice_deactivate(struct llcc_slice_desc *desc) 171 + { 172 + u32 act_ctrl_val; 173 + int ret; 174 + 175 + mutex_lock(&drv_data->lock); 176 + if (!test_bit(desc->slice_id, drv_data->bitmap)) { 177 + mutex_unlock(&drv_data->lock); 178 + return 0; 179 + } 180 + act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT; 181 + 182 + ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val, 183 + ACTIVATE); 184 + if (ret) { 185 + mutex_unlock(&drv_data->lock); 186 + return ret; 187 + } 188 + 189 + __clear_bit(desc->slice_id, drv_data->bitmap); 190 + mutex_unlock(&drv_data->lock); 191 + 192 + return ret; 193 + } 194 + EXPORT_SYMBOL_GPL(llcc_slice_deactivate); 195 + 196 + /** 197 + * llcc_get_slice_id - return the slice id 198 + * @desc: Pointer to llcc slice descriptor 199 + */ 200 + int llcc_get_slice_id(struct llcc_slice_desc *desc) 201 + { 202 + return desc->slice_id; 203 + } 204 + EXPORT_SYMBOL_GPL(llcc_get_slice_id); 205 + 206 + /** 207 + * llcc_get_slice_size - return the slice id 208 + * @desc: Pointer to llcc slice descriptor 209 + */ 210 + size_t llcc_get_slice_size(struct llcc_slice_desc *desc) 211 + { 212 + return desc->slice_size; 213 + } 214 + EXPORT_SYMBOL_GPL(llcc_get_slice_size); 215 + 216 + static int qcom_llcc_cfg_program(struct platform_device *pdev) 217 + { 218 + int i; 219 + u32 attr1_cfg; 220 + u32 attr0_cfg; 221 + u32 attr1_val; 222 + u32 attr0_val; 223 + u32 max_cap_cacheline; 224 + u32 sz; 225 + int ret; 226 + const struct llcc_slice_config *llcc_table; 227 + struct llcc_slice_desc desc; 228 + u32 bcast_off = drv_data->bcast_off; 229 + 230 + sz = drv_data->cfg_size; 231 + llcc_table = drv_data->cfg; 232 + 233 + for (i = 0; i < sz; i++) { 234 + attr1_cfg = bcast_off + 235 + LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); 236 + attr0_cfg = bcast_off + 237 + LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id); 238 + 239 + attr1_val = llcc_table[i].cache_mode; 240 + attr1_val |= llcc_table[i].probe_target_ways << 241 + ATTR1_PROBE_TARGET_WAYS_SHIFT; 242 + attr1_val |= llcc_table[i].fixed_size << 243 + ATTR1_FIXED_SIZE_SHIFT; 244 + attr1_val |= llcc_table[i].priority << 245 + ATTR1_PRIORITY_SHIFT; 246 + 247 + max_cap_cacheline = MAX_CAP_TO_BYTES(llcc_table[i].max_cap); 248 + 249 + /* LLCC instances can vary for each target. 250 + * The SW writes to broadcast register which gets propagated 251 + * to each llcc instace (llcc0,.. llccN). 252 + * Since the size of the memory is divided equally amongst the 253 + * llcc instances, we need to configure the max cap accordingly. 254 + */ 255 + max_cap_cacheline = max_cap_cacheline / drv_data->num_banks; 256 + max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT; 257 + attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT; 258 + 259 + attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK; 260 + attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT; 261 + 262 + ret = regmap_write(drv_data->regmap, attr1_cfg, attr1_val); 263 + if (ret) 264 + return ret; 265 + ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val); 266 + if (ret) 267 + return ret; 268 + if (llcc_table[i].activate_on_init) { 269 + desc.slice_id = llcc_table[i].slice_id; 270 + ret = llcc_slice_activate(&desc); 271 + } 272 + } 273 + return ret; 274 + } 275 + 276 + int qcom_llcc_probe(struct platform_device *pdev, 277 + const struct llcc_slice_config *llcc_cfg, u32 sz) 278 + { 279 + u32 num_banks; 280 + struct device *dev = &pdev->dev; 281 + struct resource *res; 282 + void __iomem *base; 283 + int ret, i; 284 + 285 + drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); 286 + if (!drv_data) 287 + return -ENOMEM; 288 + 289 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 290 + base = devm_ioremap_resource(&pdev->dev, res); 291 + if (IS_ERR(base)) 292 + return PTR_ERR(base); 293 + 294 + drv_data->regmap = devm_regmap_init_mmio(dev, base, 295 + &llcc_regmap_config); 296 + if (IS_ERR(drv_data->regmap)) 297 + return PTR_ERR(drv_data->regmap); 298 + 299 + ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0, 300 + &num_banks); 301 + if (ret) 302 + return ret; 303 + 304 + num_banks &= LLCC_LB_CNT_MASK; 305 + num_banks >>= LLCC_LB_CNT_SHIFT; 306 + drv_data->num_banks = num_banks; 307 + 308 + for (i = 0; i < sz; i++) 309 + if (llcc_cfg[i].slice_id > drv_data->max_slices) 310 + drv_data->max_slices = llcc_cfg[i].slice_id; 311 + 312 + drv_data->offsets = devm_kcalloc(dev, num_banks, sizeof(u32), 313 + GFP_KERNEL); 314 + if (!drv_data->offsets) 315 + return -ENOMEM; 316 + 317 + for (i = 0; i < num_banks; i++) 318 + drv_data->offsets[i] = i * BANK_OFFSET_STRIDE; 319 + 320 + drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE; 321 + 322 + drv_data->bitmap = devm_kcalloc(dev, 323 + BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long), 324 + GFP_KERNEL); 325 + if (!drv_data->bitmap) 326 + return -ENOMEM; 327 + 328 + drv_data->cfg = llcc_cfg; 329 + drv_data->cfg_size = sz; 330 + mutex_init(&drv_data->lock); 331 + platform_set_drvdata(pdev, drv_data); 332 + 333 + return qcom_llcc_cfg_program(pdev); 334 + } 335 + EXPORT_SYMBOL_GPL(qcom_llcc_probe);
+180
include/linux/soc/qcom/llcc-qcom.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. 4 + * 5 + */ 6 + 7 + #include <linux/platform_device.h> 8 + #ifndef __LLCC_QCOM__ 9 + #define __LLCC_QCOM__ 10 + 11 + #define LLCC_CPUSS 1 12 + #define LLCC_VIDSC0 2 13 + #define LLCC_VIDSC1 3 14 + #define LLCC_ROTATOR 4 15 + #define LLCC_VOICE 5 16 + #define LLCC_AUDIO 6 17 + #define LLCC_MDMHPGRW 7 18 + #define LLCC_MDM 8 19 + #define LLCC_CMPT 10 20 + #define LLCC_GPUHTW 11 21 + #define LLCC_GPU 12 22 + #define LLCC_MMUHWT 13 23 + #define LLCC_CMPTDMA 15 24 + #define LLCC_DISP 16 25 + #define LLCC_VIDFW 17 26 + #define LLCC_MDMHPFX 20 27 + #define LLCC_MDMPNG 21 28 + #define LLCC_AUDHW 22 29 + 30 + /** 31 + * llcc_slice_desc - Cache slice descriptor 32 + * @slice_id: llcc slice id 33 + * @slice_size: Size allocated for the llcc slice 34 + */ 35 + struct llcc_slice_desc { 36 + u32 slice_id; 37 + size_t slice_size; 38 + }; 39 + 40 + /** 41 + * llcc_slice_config - Data associated with the llcc slice 42 + * @usecase_id: usecase id for which the llcc slice is used 43 + * @slice_id: llcc slice id assigned to each slice 44 + * @max_cap: maximum capacity of the llcc slice 45 + * @priority: priority of the llcc slice 46 + * @fixed_size: whether the llcc slice can grow beyond its size 47 + * @bonus_ways: bonus ways associated with llcc slice 48 + * @res_ways: reserved ways associated with llcc slice 49 + * @cache_mode: mode of the llcc slice 50 + * @probe_target_ways: Probe only reserved and bonus ways on a cache miss 51 + * @dis_cap_alloc: Disable capacity based allocation 52 + * @retain_on_pc: Retain through power collapse 53 + * @activate_on_init: activate the slice on init 54 + */ 55 + struct llcc_slice_config { 56 + u32 usecase_id; 57 + u32 slice_id; 58 + u32 max_cap; 59 + u32 priority; 60 + bool fixed_size; 61 + u32 bonus_ways; 62 + u32 res_ways; 63 + u32 cache_mode; 64 + u32 probe_target_ways; 65 + bool dis_cap_alloc; 66 + bool retain_on_pc; 67 + bool activate_on_init; 68 + }; 69 + 70 + /** 71 + * llcc_drv_data - Data associated with the llcc driver 72 + * @regmap: regmap associated with the llcc device 73 + * @cfg: pointer to the data structure for slice configuration 74 + * @lock: mutex associated with each slice 75 + * @cfg_size: size of the config data table 76 + * @max_slices: max slices as read from device tree 77 + * @bcast_off: Offset of the broadcast bank 78 + * @num_banks: Number of llcc banks 79 + * @bitmap: Bit map to track the active slice ids 80 + * @offsets: Pointer to the bank offsets array 81 + */ 82 + struct llcc_drv_data { 83 + struct regmap *regmap; 84 + const struct llcc_slice_config *cfg; 85 + struct mutex lock; 86 + u32 cfg_size; 87 + u32 max_slices; 88 + u32 bcast_off; 89 + u32 num_banks; 90 + unsigned long *bitmap; 91 + u32 *offsets; 92 + }; 93 + 94 + #if IS_ENABLED(CONFIG_QCOM_LLCC) 95 + /** 96 + * llcc_slice_getd - get llcc slice descriptor 97 + * @uid: usecase_id of the client 98 + */ 99 + struct llcc_slice_desc *llcc_slice_getd(u32 uid); 100 + 101 + /** 102 + * llcc_slice_putd - llcc slice descritpor 103 + * @desc: Pointer to llcc slice descriptor 104 + */ 105 + void llcc_slice_putd(struct llcc_slice_desc *desc); 106 + 107 + /** 108 + * llcc_get_slice_id - get slice id 109 + * @desc: Pointer to llcc slice descriptor 110 + */ 111 + int llcc_get_slice_id(struct llcc_slice_desc *desc); 112 + 113 + /** 114 + * llcc_get_slice_size - llcc slice size 115 + * @desc: Pointer to llcc slice descriptor 116 + */ 117 + size_t llcc_get_slice_size(struct llcc_slice_desc *desc); 118 + 119 + /** 120 + * llcc_slice_activate - Activate the llcc slice 121 + * @desc: Pointer to llcc slice descriptor 122 + */ 123 + int llcc_slice_activate(struct llcc_slice_desc *desc); 124 + 125 + /** 126 + * llcc_slice_deactivate - Deactivate the llcc slice 127 + * @desc: Pointer to llcc slice descriptor 128 + */ 129 + int llcc_slice_deactivate(struct llcc_slice_desc *desc); 130 + 131 + /** 132 + * qcom_llcc_probe - program the sct table 133 + * @pdev: platform device pointer 134 + * @table: soc sct table 135 + * @sz: Size of the config table 136 + */ 137 + int qcom_llcc_probe(struct platform_device *pdev, 138 + const struct llcc_slice_config *table, u32 sz); 139 + #else 140 + static inline struct llcc_slice_desc *llcc_slice_getd(u32 uid) 141 + { 142 + return NULL; 143 + } 144 + 145 + static inline void llcc_slice_putd(struct llcc_slice_desc *desc) 146 + { 147 + 148 + }; 149 + 150 + static inline int llcc_get_slice_id(struct llcc_slice_desc *desc) 151 + { 152 + return -EINVAL; 153 + } 154 + 155 + static inline size_t llcc_get_slice_size(struct llcc_slice_desc *desc) 156 + { 157 + return 0; 158 + } 159 + static inline int llcc_slice_activate(struct llcc_slice_desc *desc) 160 + { 161 + return -EINVAL; 162 + } 163 + 164 + static inline int llcc_slice_deactivate(struct llcc_slice_desc *desc) 165 + { 166 + return -EINVAL; 167 + } 168 + static inline int qcom_llcc_probe(struct platform_device *pdev, 169 + const struct llcc_slice_config *table, u32 sz) 170 + { 171 + return -ENODEV; 172 + } 173 + 174 + static inline int qcom_llcc_remove(struct platform_device *pdev) 175 + { 176 + return -ENODEV; 177 + } 178 + #endif 179 + 180 + #endif