]> Git Repo - linux.git/blob - drivers/soc/qcom/llcc-qcom.c
x86/alternative: Make custom return thunk unconditional
[linux.git] / drivers / soc / qcom / llcc-qcom.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
4  *
5  */
6
7 #include <linux/bitfield.h>
8 #include <linux/bitmap.h>
9 #include <linux/bitops.h>
10 #include <linux/device.h>
11 #include <linux/io.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/of.h>
16 #include <linux/of_device.h>
17 #include <linux/regmap.h>
18 #include <linux/sizes.h>
19 #include <linux/slab.h>
20 #include <linux/soc/qcom/llcc-qcom.h>
21
22 #define ACTIVATE                      BIT(0)
23 #define DEACTIVATE                    BIT(1)
24 #define ACT_CLEAR                     BIT(0)
25 #define ACT_COMPLETE                  BIT(4)
26 #define ACT_CTRL_OPCODE_ACTIVATE      BIT(0)
27 #define ACT_CTRL_OPCODE_DEACTIVATE    BIT(1)
28 #define ACT_CTRL_ACT_TRIG             BIT(0)
29 #define ACT_CTRL_OPCODE_SHIFT         0x01
30 #define ATTR1_PROBE_TARGET_WAYS_SHIFT 0x02
31 #define ATTR1_FIXED_SIZE_SHIFT        0x03
32 #define ATTR1_PRIORITY_SHIFT          0x04
33 #define ATTR1_MAX_CAP_SHIFT           0x10
34 #define ATTR0_RES_WAYS_MASK           GENMASK(15, 0)
35 #define ATTR0_BONUS_WAYS_MASK         GENMASK(31, 16)
36 #define ATTR0_BONUS_WAYS_SHIFT        0x10
37 #define LLCC_STATUS_READ_DELAY        100
38
39 #define CACHE_LINE_SIZE_SHIFT         6
40
41 #define LLCC_LB_CNT_MASK              GENMASK(31, 28)
42 #define LLCC_LB_CNT_SHIFT             28
43
44 #define MAX_CAP_TO_BYTES(n)           (n * SZ_1K)
45 #define LLCC_TRP_ACT_CTRLn(n)         (n * SZ_4K)
46 #define LLCC_TRP_ACT_CLEARn(n)        (8 + n * SZ_4K)
47 #define LLCC_TRP_STATUSn(n)           (4 + n * SZ_4K)
48 #define LLCC_TRP_ATTR0_CFGn(n)        (0x21000 + SZ_8 * n)
49 #define LLCC_TRP_ATTR1_CFGn(n)        (0x21004 + SZ_8 * n)
50 #define LLCC_TRP_ATTR2_CFGn(n)        (0x21100 + SZ_8 * n)
51
52 #define LLCC_TRP_SCID_DIS_CAP_ALLOC   0x21f00
53 #define LLCC_TRP_PCB_ACT              0x21f04
54 #define LLCC_TRP_ALGO_CFG1            0x21f0c
55 #define LLCC_TRP_ALGO_CFG2            0x21f10
56 #define LLCC_TRP_ALGO_CFG3            0x21f14
57 #define LLCC_TRP_ALGO_CFG4            0x21f18
58 #define LLCC_TRP_ALGO_CFG5            0x21f1c
59 #define LLCC_TRP_WRSC_EN              0x21f20
60 #define LLCC_TRP_ALGO_CFG6            0x21f24
61 #define LLCC_TRP_ALGO_CFG7            0x21f28
62 #define LLCC_TRP_WRSC_CACHEABLE_EN    0x21f2c
63 #define LLCC_TRP_ALGO_CFG8            0x21f30
64
65 #define LLCC_VERSION_2_0_0_0          0x02000000
66 #define LLCC_VERSION_2_1_0_0          0x02010000
67 #define LLCC_VERSION_4_1_0_0          0x04010000
68
69 /**
70  * struct llcc_slice_config - Data associated with the llcc slice
71  * @usecase_id: Unique id for the client's use case
72  * @slice_id: llcc slice id for each client
73  * @max_cap: The maximum capacity of the cache slice provided in KB
74  * @priority: Priority of the client used to select victim line for replacement
75  * @fixed_size: Boolean indicating if the slice has a fixed capacity
76  * @bonus_ways: Bonus ways are additional ways to be used for any slice,
77  *              if client ends up using more than reserved cache ways. Bonus
78  *              ways are allocated only if they are not reserved for some
79  *              other client.
80  * @res_ways: Reserved ways for the cache slice, the reserved ways cannot
81  *              be used by any other client than the one its assigned to.
82  * @cache_mode: Each slice operates as a cache, this controls the mode of the
83  *             slice: normal or TCM(Tightly Coupled Memory)
84  * @probe_target_ways: Determines what ways to probe for access hit. When
85  *                    configured to 1 only bonus and reserved ways are probed.
86  *                    When configured to 0 all ways in llcc are probed.
87  * @dis_cap_alloc: Disable capacity based allocation for a client
88  * @retain_on_pc: If this bit is set and client has maintained active vote
89  *               then the ways assigned to this client are not flushed on power
90  *               collapse.
91  * @activate_on_init: Activate the slice immediately after it is programmed
92  * @write_scid_en: Bit enables write cache support for a given scid.
93  * @write_scid_cacheable_en: Enables write cache cacheable support for a
94  *                           given scid (not supported on v2 or older hardware).
95  */
96 struct llcc_slice_config {
97         u32 usecase_id;
98         u32 slice_id;
99         u32 max_cap;
100         u32 priority;
101         bool fixed_size;
102         u32 bonus_ways;
103         u32 res_ways;
104         u32 cache_mode;
105         u32 probe_target_ways;
106         bool dis_cap_alloc;
107         bool retain_on_pc;
108         bool activate_on_init;
109         bool write_scid_en;
110         bool write_scid_cacheable_en;
111         bool stale_en;
112         bool stale_cap_en;
113         bool mru_uncap_en;
114         bool mru_rollover;
115         bool alloc_oneway_en;
116         bool ovcap_en;
117         bool ovcap_prio;
118         bool vict_prio;
119 };
120
121 struct qcom_llcc_config {
122         const struct llcc_slice_config *sct_data;
123         const u32 *reg_offset;
124         const struct llcc_edac_reg_offset *edac_reg_offset;
125         int size;
126         bool need_llcc_cfg;
127         bool no_edac;
128 };
129
130 enum llcc_reg_offset {
131         LLCC_COMMON_HW_INFO,
132         LLCC_COMMON_STATUS0,
133 };
134
135 static const struct llcc_slice_config sc7180_data[] =  {
136         { LLCC_CPUSS,    1,  256, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 1 },
137         { LLCC_MDM,      8,  128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
138         { LLCC_GPUHTW,   11, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
139         { LLCC_GPU,      12, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 },
140 };
141
142 static const struct llcc_slice_config sc7280_data[] =  {
143         { LLCC_CPUSS,    1,  768, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 1, 0},
144         { LLCC_MDMHPGRW, 7,  512, 2, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
145         { LLCC_CMPT,     10, 768, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
146         { LLCC_GPUHTW,   11, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
147         { LLCC_GPU,      12, 512, 1, 0, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
148         { LLCC_MMUHWT,   13, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 0, 1, 0},
149         { LLCC_MDMPNG,   21, 768, 0, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
150         { LLCC_WLHW,     24, 256, 1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
151         { LLCC_MODPE,    29, 64,  1, 1, 0x3f, 0x0, 0, 0, 0, 1, 0, 0},
152 };
153
154 static const struct llcc_slice_config sc8180x_data[] = {
155         { LLCC_CPUSS,    1, 6144,  1, 1, 0xfff, 0x0,   0, 0, 0, 1, 1 },
156         { LLCC_VIDSC0,   2, 512,   2, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
157         { LLCC_VIDSC1,   3, 512,   2, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
158         { LLCC_AUDIO,    6, 1024,  1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
159         { LLCC_MDMHPGRW, 7, 3072,  1, 1, 0x3ff, 0xc00, 0, 0, 0, 1, 0 },
160         { LLCC_MDM,      8, 3072,  1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
161         { LLCC_MODHW,    9, 1024,  1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
162         { LLCC_CMPT,     10, 6144, 1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
163         { LLCC_GPUHTW,   11, 1024, 1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
164         { LLCC_GPU,      12, 5120, 1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
165         { LLCC_MMUHWT,   13, 1024, 1, 1, 0xfff, 0x0,   0, 0, 0, 0, 1 },
166         { LLCC_CMPTDMA,  15, 6144, 1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
167         { LLCC_DISP,     16, 6144, 1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
168         { LLCC_VIDFW,    17, 1024, 1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
169         { LLCC_MDMHPFX,  20, 1024, 2, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
170         { LLCC_MDMPNG,   21, 1024, 0, 1, 0xc,   0x0,   0, 0, 0, 1, 0 },
171         { LLCC_AUDHW,    22, 1024, 1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
172         { LLCC_NPU,      23, 6144, 1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
173         { LLCC_WLHW,     24, 6144, 1, 1, 0xfff, 0x0,   0, 0, 0, 1, 0 },
174         { LLCC_MODPE,    29, 512,  1, 1, 0xc,   0x0,   0, 0, 0, 1, 0 },
175         { LLCC_APTCM,    30, 512,  3, 1, 0x0,   0x1,   1, 0, 0, 1, 0 },
176         { LLCC_WRCACHE,  31, 128,  1, 1, 0xfff, 0x0,   0, 0, 0, 0, 0 },
177 };
178
179 static const struct llcc_slice_config sc8280xp_data[] = {
180         { LLCC_CPUSS,    1,  6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 },
181         { LLCC_VIDSC0,   2,  512,  3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
182         { LLCC_AUDIO,    6,  1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
183         { LLCC_CMPT,     10, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
184         { LLCC_GPUHTW,   11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
185         { LLCC_GPU,      12, 4096, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 1 },
186         { LLCC_MMUHWT,   13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
187         { LLCC_DISP,     16, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
188         { LLCC_AUDHW,    22, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
189         { LLCC_DRE,      26, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
190         { LLCC_CVP,      28, 512,  3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
191         { LLCC_APTCM,    30, 1024, 3, 1, 0x0,   0x1, 1, 0, 0, 1, 0, 0 },
192         { LLCC_WRCACHE,  31, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
193         { LLCC_CVPFW,    17, 512,  1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
194         { LLCC_CPUSS1,   3, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
195         { LLCC_CPUHWT,   5, 512,  1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
196 };
197
198 static const struct llcc_slice_config sdm845_data[] =  {
199         { LLCC_CPUSS,    1,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 1 },
200         { LLCC_VIDSC0,   2,  512,  2, 1, 0x0,   0x0f0, 0, 0, 1, 1, 0 },
201         { LLCC_VIDSC1,   3,  512,  2, 1, 0x0,   0x0f0, 0, 0, 1, 1, 0 },
202         { LLCC_ROTATOR,  4,  563,  2, 1, 0x0,   0x00e, 2, 0, 1, 1, 0 },
203         { LLCC_VOICE,    5,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
204         { LLCC_AUDIO,    6,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
205         { LLCC_MDMHPGRW, 7,  1024, 2, 0, 0xfc,  0xf00, 0, 0, 1, 1, 0 },
206         { LLCC_MDM,      8,  2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
207         { LLCC_CMPT,     10, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
208         { LLCC_GPUHTW,   11, 512,  1, 1, 0xc,   0x0,   0, 0, 1, 1, 0 },
209         { LLCC_GPU,      12, 2304, 1, 0, 0xff0, 0x2,   0, 0, 1, 1, 0 },
210         { LLCC_MMUHWT,   13, 256,  2, 0, 0x0,   0x1,   0, 0, 1, 0, 1 },
211         { LLCC_CMPTDMA,  15, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
212         { LLCC_DISP,     16, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
213         { LLCC_VIDFW,    17, 2816, 1, 0, 0xffc, 0x2,   0, 0, 1, 1, 0 },
214         { LLCC_MDMHPFX,  20, 1024, 2, 1, 0x0,   0xf00, 0, 0, 1, 1, 0 },
215         { LLCC_MDMPNG,   21, 1024, 0, 1, 0x1e,  0x0,   0, 0, 1, 1, 0 },
216         { LLCC_AUDHW,    22, 1024, 1, 1, 0xffc, 0x2,   0, 0, 1, 1, 0 },
217 };
218
219 static const struct llcc_slice_config sm6350_data[] =  {
220         { LLCC_CPUSS,    1,  768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 1 },
221         { LLCC_MDM,      8,  512, 2, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
222         { LLCC_GPUHTW,   11, 256, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
223         { LLCC_GPU,      12, 512, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
224         { LLCC_MDMPNG,   21, 768, 0, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
225         { LLCC_NPU,      23, 768, 1, 0, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
226         { LLCC_MODPE,    29,  64, 1, 1, 0xFFF, 0x0, 0, 0, 0, 0, 1, 0 },
227 };
228
229 static const struct llcc_slice_config sm7150_data[] =  {
230         { LLCC_CPUSS,    1,  512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 1 },
231         { LLCC_MDM,      8,  128, 2, 0, 0xF, 0x0, 0, 0, 0, 1, 0 },
232         { LLCC_GPUHTW,   11, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 },
233         { LLCC_GPU,      12, 256, 1, 1, 0xF, 0x0, 0, 0, 0, 1, 0 },
234         { LLCC_NPU,      23, 512, 1, 0, 0xF, 0x0, 0, 0, 0, 1, 0 },
235 };
236
237 static const struct llcc_slice_config sm8150_data[] =  {
238         {  LLCC_CPUSS,    1, 3072, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 1 },
239         {  LLCC_VIDSC0,   2, 512,  2, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
240         {  LLCC_VIDSC1,   3, 512,  2, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
241         {  LLCC_AUDIO,    6, 1024, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
242         {  LLCC_MDMHPGRW, 7, 3072, 1, 0, 0xFF,  0xF00, 0, 0, 0, 1, 0 },
243         {  LLCC_MDM,      8, 3072, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
244         {  LLCC_MODHW,    9, 1024, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
245         {  LLCC_CMPT,    10, 3072, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
246         {  LLCC_GPUHTW , 11, 512,  1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
247         {  LLCC_GPU,     12, 2560, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
248         {  LLCC_MMUHWT,  13, 1024, 1, 1, 0xFFF, 0x0,   0, 0, 0, 0, 1 },
249         {  LLCC_CMPTDMA, 15, 3072, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
250         {  LLCC_DISP,    16, 3072, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
251         {  LLCC_MDMHPFX, 20, 1024, 2, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
252         {  LLCC_MDMHPFX, 21, 1024, 0, 1, 0xF,   0x0,   0, 0, 0, 1, 0 },
253         {  LLCC_AUDHW,   22, 1024, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
254         {  LLCC_NPU,     23, 3072, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
255         {  LLCC_WLHW,    24, 3072, 1, 1, 0xFFF, 0x0,   0, 0, 0, 1, 0 },
256         {  LLCC_MODPE,   29, 256,  1, 1, 0xF,   0x0,   0, 0, 0, 1, 0 },
257         {  LLCC_APTCM,   30, 256,  3, 1, 0x0,   0x1,   1, 0, 0, 1, 0 },
258         {  LLCC_WRCACHE, 31, 128,  1, 1, 0xFFF, 0x0,   0, 0, 0, 0, 0 },
259 };
260
261 static const struct llcc_slice_config sm8250_data[] =  {
262         { LLCC_CPUSS,    1, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 },
263         { LLCC_VIDSC0,   2, 512,  3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
264         { LLCC_AUDIO,    6, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
265         { LLCC_CMPT,    10, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
266         { LLCC_GPUHTW,  11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
267         { LLCC_GPU,     12, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 1 },
268         { LLCC_MMUHWT,  13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
269         { LLCC_CMPTDMA, 15, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
270         { LLCC_DISP,    16, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
271         { LLCC_VIDFW,   17, 512,  1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
272         { LLCC_AUDHW,   22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
273         { LLCC_NPU,     23, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
274         { LLCC_WLHW,    24, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
275         { LLCC_CVP,     28, 256,  3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
276         { LLCC_APTCM,   30, 128,  3, 0, 0x0,   0x3, 1, 0, 0, 1, 0, 0 },
277         { LLCC_WRCACHE, 31, 256,  1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
278 };
279
280 static const struct llcc_slice_config sm8350_data[] =  {
281         { LLCC_CPUSS,    1, 3072,  1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 1 },
282         { LLCC_VIDSC0,   2, 512,   3, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
283         { LLCC_AUDIO,    6, 1024,  1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 },
284         { LLCC_MDMHPGRW, 7, 1024,  3, 0, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
285         { LLCC_MODHW,    9, 1024,  1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
286         { LLCC_CMPT,     10, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
287         { LLCC_GPUHTW,   11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
288         { LLCC_GPU,      12, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 },
289         { LLCC_MMUHWT,   13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 },
290         { LLCC_DISP,     16, 3072, 2, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
291         { LLCC_MDMPNG,   21, 1024, 0, 1, 0xf,   0x0, 0, 0, 0, 0, 1, 0 },
292         { LLCC_AUDHW,    22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
293         { LLCC_CVP,      28, 512,  3, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
294         { LLCC_MODPE,    29, 256,  1, 1, 0xf,   0x0, 0, 0, 0, 0, 1, 0 },
295         { LLCC_APTCM,    30, 1024, 3, 1, 0x0,   0x1, 1, 0, 0, 0, 1, 0 },
296         { LLCC_WRCACHE,  31, 512,  1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 },
297         { LLCC_CVPFW,    17, 512,  1, 0, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
298         { LLCC_CPUSS1,   3, 1024,  1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
299         { LLCC_CPUHWT,   5, 512,   1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 },
300 };
301
302 static const struct llcc_slice_config sm8450_data[] =  {
303         {LLCC_CPUSS,     1, 3072, 1, 0, 0xFFFF, 0x0,   0, 0, 0, 1, 1, 0, 0 },
304         {LLCC_VIDSC0,    2,  512, 3, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
305         {LLCC_AUDIO,     6, 1024, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0 },
306         {LLCC_MDMHPGRW,  7, 1024, 3, 0, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
307         {LLCC_MODHW,     9, 1024, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
308         {LLCC_CMPT,     10, 4096, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
309         {LLCC_GPUHTW,   11,  512, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
310         {LLCC_GPU,      12, 2048, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 1, 0 },
311         {LLCC_MMUHWT,   13,  768, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 0, 1, 0, 0 },
312         {LLCC_DISP,     16, 4096, 2, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
313         {LLCC_MDMPNG,   21, 1024, 1, 1, 0xF000, 0x0,   0, 0, 0, 1, 0, 0, 0 },
314         {LLCC_AUDHW,    22, 1024, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0 },
315         {LLCC_CVP,      28,  256, 3, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
316         {LLCC_MODPE,    29,   64, 1, 1, 0xF000, 0x0,   0, 0, 0, 1, 0, 0, 0 },
317         {LLCC_APTCM,    30, 1024, 3, 1, 0x0,    0xF0,  1, 0, 0, 1, 0, 0, 0 },
318         {LLCC_WRCACHE,  31,  512, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 0, 1, 0, 0 },
319         {LLCC_CVPFW,    17,  512, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
320         {LLCC_CPUSS1,    3, 1024, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
321         {LLCC_CAMEXP0,   4,  256, 3, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
322         {LLCC_CPUMTE,   23,  256, 1, 1, 0x0FFF, 0x0,   0, 0, 0, 0, 1, 0, 0 },
323         {LLCC_CPUHWT,    5,  512, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 1, 0, 0 },
324         {LLCC_CAMEXP1,  27,  256, 3, 1, 0xFFFF, 0x0,   0, 0, 0, 1, 0, 0, 0 },
325         {LLCC_AENPU,     8, 2048, 1, 1, 0xFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0 },
326 };
327
328 static const struct llcc_slice_config sm8550_data[] =  {
329         {LLCC_CPUSS,     1, 5120, 1, 0, 0xFFFFFF, 0x0,   0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
330         {LLCC_VIDSC0,    2,  512, 4, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
331         {LLCC_AUDIO,     6, 1024, 1, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
332         {LLCC_MDMHPGRW, 25, 1024, 4, 0, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
333         {LLCC_MODHW,    26, 1024, 1, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
334         {LLCC_CMPT,     10, 4096, 1, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
335         {LLCC_GPUHTW,   11,  512, 1, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
336         {LLCC_GPU,       9, 3096, 1, 0, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, },
337         {LLCC_MMUHWT,   18,  768, 1, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
338         {LLCC_DISP,     16, 6144, 1, 1, 0xFFFFFF, 0x0,   2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
339         {LLCC_MDMPNG,   27, 1024, 0, 1, 0xF00000, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
340         {LLCC_AUDHW,    22, 1024, 1, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
341         {LLCC_CVP,       8,  256, 4, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
342         {LLCC_MODPE,    29,   64, 1, 1, 0xF00000, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, },
343         {LLCC_WRCACHE,  31,  512, 1, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
344         {LLCC_CAMEXP0,   4,  256, 4, 1,      0xF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
345         {LLCC_CPUHWT,    5,  512, 1, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
346         {LLCC_CAMEXP1,   7, 3200, 3, 1, 0xFFFFF0, 0x0,   2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
347         {LLCC_CMPTHCP,  17,  256, 4, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
348         {LLCC_LCPDARE,  30,  128, 4, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, },
349         {LLCC_AENPU,     3, 3072, 1, 1, 0xFE01FF, 0x0,   2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
350         {LLCC_ISLAND1,  12, 1792, 7, 1,   0xFE00, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
351         {LLCC_ISLAND4,  15,  256, 7, 1,  0x10000, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
352         {LLCC_CAMEXP2,  19, 3200, 3, 1, 0xFFFFF0, 0x0,   2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
353         {LLCC_CAMEXP3,  20, 3200, 2, 1, 0xFFFFF0, 0x0,   2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
354         {LLCC_CAMEXP4,  21, 3200, 2, 1, 0xFFFFF0, 0x0,   2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
355         {LLCC_DISP_WB,  23, 1024, 4, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
356         {LLCC_DISP_1,   24, 6144, 1, 1, 0xFFFFFF, 0x0,   2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
357         {LLCC_VIDVSP,   28,  256, 4, 1, 0xFFFFFF, 0x0,   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
358 };
359
360 static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = {
361         .trp_ecc_error_status0 = 0x20344,
362         .trp_ecc_error_status1 = 0x20348,
363         .trp_ecc_sb_err_syn0 = 0x2304c,
364         .trp_ecc_db_err_syn0 = 0x20370,
365         .trp_ecc_error_cntr_clear = 0x20440,
366         .trp_interrupt_0_status = 0x20480,
367         .trp_interrupt_0_clear = 0x20484,
368         .trp_interrupt_0_enable = 0x20488,
369
370         /* LLCC Common registers */
371         .cmn_status0 = 0x3000c,
372         .cmn_interrupt_0_enable = 0x3001c,
373         .cmn_interrupt_2_enable = 0x3003c,
374
375         /* LLCC DRP registers */
376         .drp_ecc_error_cfg = 0x40000,
377         .drp_ecc_error_cntr_clear = 0x40004,
378         .drp_interrupt_status = 0x41000,
379         .drp_interrupt_clear = 0x41008,
380         .drp_interrupt_enable = 0x4100c,
381         .drp_ecc_error_status0 = 0x42044,
382         .drp_ecc_error_status1 = 0x42048,
383         .drp_ecc_sb_err_syn0 = 0x4204c,
384         .drp_ecc_db_err_syn0 = 0x42070,
385 };
386
387 static const struct llcc_edac_reg_offset llcc_v2_1_edac_reg_offset = {
388         .trp_ecc_error_status0 = 0x20344,
389         .trp_ecc_error_status1 = 0x20348,
390         .trp_ecc_sb_err_syn0 = 0x2034c,
391         .trp_ecc_db_err_syn0 = 0x20370,
392         .trp_ecc_error_cntr_clear = 0x20440,
393         .trp_interrupt_0_status = 0x20480,
394         .trp_interrupt_0_clear = 0x20484,
395         .trp_interrupt_0_enable = 0x20488,
396
397         /* LLCC Common registers */
398         .cmn_status0 = 0x3400c,
399         .cmn_interrupt_0_enable = 0x3401c,
400         .cmn_interrupt_2_enable = 0x3403c,
401
402         /* LLCC DRP registers */
403         .drp_ecc_error_cfg = 0x50000,
404         .drp_ecc_error_cntr_clear = 0x50004,
405         .drp_interrupt_status = 0x50020,
406         .drp_interrupt_clear = 0x50028,
407         .drp_interrupt_enable = 0x5002c,
408         .drp_ecc_error_status0 = 0x520f4,
409         .drp_ecc_error_status1 = 0x520f8,
410         .drp_ecc_sb_err_syn0 = 0x520fc,
411         .drp_ecc_db_err_syn0 = 0x52120,
412 };
413
414 /* LLCC register offset starting from v1.0.0 */
415 static const u32 llcc_v1_reg_offset[] = {
416         [LLCC_COMMON_HW_INFO]   = 0x00030000,
417         [LLCC_COMMON_STATUS0]   = 0x0003000c,
418 };
419
420 /* LLCC register offset starting from v2.0.1 */
421 static const u32 llcc_v2_1_reg_offset[] = {
422         [LLCC_COMMON_HW_INFO]   = 0x00034000,
423         [LLCC_COMMON_STATUS0]   = 0x0003400c,
424 };
425
426 static const struct qcom_llcc_config sc7180_cfg = {
427         .sct_data       = sc7180_data,
428         .size           = ARRAY_SIZE(sc7180_data),
429         .need_llcc_cfg  = true,
430         .reg_offset     = llcc_v1_reg_offset,
431         .edac_reg_offset = &llcc_v1_edac_reg_offset,
432 };
433
434 static const struct qcom_llcc_config sc7280_cfg = {
435         .sct_data       = sc7280_data,
436         .size           = ARRAY_SIZE(sc7280_data),
437         .need_llcc_cfg  = true,
438         .reg_offset     = llcc_v1_reg_offset,
439         .edac_reg_offset = &llcc_v1_edac_reg_offset,
440 };
441
442 static const struct qcom_llcc_config sc8180x_cfg = {
443         .sct_data       = sc8180x_data,
444         .size           = ARRAY_SIZE(sc8180x_data),
445         .need_llcc_cfg  = true,
446         .reg_offset     = llcc_v1_reg_offset,
447         .edac_reg_offset = &llcc_v1_edac_reg_offset,
448 };
449
450 static const struct qcom_llcc_config sc8280xp_cfg = {
451         .sct_data       = sc8280xp_data,
452         .size           = ARRAY_SIZE(sc8280xp_data),
453         .need_llcc_cfg  = true,
454         .reg_offset     = llcc_v1_reg_offset,
455         .edac_reg_offset = &llcc_v1_edac_reg_offset,
456 };
457
458 static const struct qcom_llcc_config sdm845_cfg = {
459         .sct_data       = sdm845_data,
460         .size           = ARRAY_SIZE(sdm845_data),
461         .need_llcc_cfg  = false,
462         .reg_offset     = llcc_v1_reg_offset,
463         .edac_reg_offset = &llcc_v1_edac_reg_offset,
464         .no_edac        = true,
465 };
466
467 static const struct qcom_llcc_config sm6350_cfg = {
468         .sct_data       = sm6350_data,
469         .size           = ARRAY_SIZE(sm6350_data),
470         .need_llcc_cfg  = true,
471         .reg_offset     = llcc_v1_reg_offset,
472         .edac_reg_offset = &llcc_v1_edac_reg_offset,
473 };
474
475 static const struct qcom_llcc_config sm7150_cfg = {
476         .sct_data       = sm7150_data,
477         .size           = ARRAY_SIZE(sm7150_data),
478         .need_llcc_cfg  = true,
479         .reg_offset     = llcc_v1_reg_offset,
480         .edac_reg_offset = &llcc_v1_edac_reg_offset,
481 };
482
483 static const struct qcom_llcc_config sm8150_cfg = {
484         .sct_data       = sm8150_data,
485         .size           = ARRAY_SIZE(sm8150_data),
486         .need_llcc_cfg  = true,
487         .reg_offset     = llcc_v1_reg_offset,
488         .edac_reg_offset = &llcc_v1_edac_reg_offset,
489 };
490
491 static const struct qcom_llcc_config sm8250_cfg = {
492         .sct_data       = sm8250_data,
493         .size           = ARRAY_SIZE(sm8250_data),
494         .need_llcc_cfg  = true,
495         .reg_offset     = llcc_v1_reg_offset,
496         .edac_reg_offset = &llcc_v1_edac_reg_offset,
497 };
498
499 static const struct qcom_llcc_config sm8350_cfg = {
500         .sct_data       = sm8350_data,
501         .size           = ARRAY_SIZE(sm8350_data),
502         .need_llcc_cfg  = true,
503         .reg_offset     = llcc_v1_reg_offset,
504         .edac_reg_offset = &llcc_v1_edac_reg_offset,
505 };
506
507 static const struct qcom_llcc_config sm8450_cfg = {
508         .sct_data       = sm8450_data,
509         .size           = ARRAY_SIZE(sm8450_data),
510         .need_llcc_cfg  = true,
511         .reg_offset     = llcc_v2_1_reg_offset,
512         .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
513 };
514
515 static const struct qcom_llcc_config sm8550_cfg = {
516         .sct_data       = sm8550_data,
517         .size           = ARRAY_SIZE(sm8550_data),
518         .need_llcc_cfg  = true,
519         .reg_offset     = llcc_v2_1_reg_offset,
520         .edac_reg_offset = &llcc_v2_1_edac_reg_offset,
521 };
522
523 static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
524
525 /**
526  * llcc_slice_getd - get llcc slice descriptor
527  * @uid: usecase_id for the client
528  *
529  * A pointer to llcc slice descriptor will be returned on success
530  * and error pointer is returned on failure
531  */
532 struct llcc_slice_desc *llcc_slice_getd(u32 uid)
533 {
534         const struct llcc_slice_config *cfg;
535         struct llcc_slice_desc *desc;
536         u32 sz, count;
537
538         if (IS_ERR(drv_data))
539                 return ERR_CAST(drv_data);
540
541         cfg = drv_data->cfg;
542         sz = drv_data->cfg_size;
543
544         for (count = 0; cfg && count < sz; count++, cfg++)
545                 if (cfg->usecase_id == uid)
546                         break;
547
548         if (count == sz || !cfg)
549                 return ERR_PTR(-ENODEV);
550
551         desc = kzalloc(sizeof(*desc), GFP_KERNEL);
552         if (!desc)
553                 return ERR_PTR(-ENOMEM);
554
555         desc->slice_id = cfg->slice_id;
556         desc->slice_size = cfg->max_cap;
557
558         return desc;
559 }
560 EXPORT_SYMBOL_GPL(llcc_slice_getd);
561
562 /**
563  * llcc_slice_putd - llcc slice descritpor
564  * @desc: Pointer to llcc slice descriptor
565  */
566 void llcc_slice_putd(struct llcc_slice_desc *desc)
567 {
568         if (!IS_ERR_OR_NULL(desc))
569                 kfree(desc);
570 }
571 EXPORT_SYMBOL_GPL(llcc_slice_putd);
572
573 static int llcc_update_act_ctrl(u32 sid,
574                                 u32 act_ctrl_reg_val, u32 status)
575 {
576         u32 act_ctrl_reg;
577         u32 act_clear_reg;
578         u32 status_reg;
579         u32 slice_status;
580         int ret;
581
582         if (IS_ERR(drv_data))
583                 return PTR_ERR(drv_data);
584
585         act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
586         act_clear_reg = LLCC_TRP_ACT_CLEARn(sid);
587         status_reg = LLCC_TRP_STATUSn(sid);
588
589         /* Set the ACTIVE trigger */
590         act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG;
591         ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
592                                 act_ctrl_reg_val);
593         if (ret)
594                 return ret;
595
596         /* Clear the ACTIVE trigger */
597         act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG;
598         ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
599                                 act_ctrl_reg_val);
600         if (ret)
601                 return ret;
602
603         if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
604                 ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
605                                       slice_status, (slice_status & ACT_COMPLETE),
606                                       0, LLCC_STATUS_READ_DELAY);
607                 if (ret)
608                         return ret;
609         }
610
611         ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
612                                       slice_status, !(slice_status & status),
613                                       0, LLCC_STATUS_READ_DELAY);
614
615         if (drv_data->version >= LLCC_VERSION_4_1_0_0)
616                 ret = regmap_write(drv_data->bcast_regmap, act_clear_reg,
617                                         ACT_CLEAR);
618
619         return ret;
620 }
621
622 /**
623  * llcc_slice_activate - Activate the llcc slice
624  * @desc: Pointer to llcc slice descriptor
625  *
626  * A value of zero will be returned on success and a negative errno will
627  * be returned in error cases
628  */
629 int llcc_slice_activate(struct llcc_slice_desc *desc)
630 {
631         int ret;
632         u32 act_ctrl_val;
633
634         if (IS_ERR(drv_data))
635                 return PTR_ERR(drv_data);
636
637         if (IS_ERR_OR_NULL(desc))
638                 return -EINVAL;
639
640         mutex_lock(&drv_data->lock);
641         if (test_bit(desc->slice_id, drv_data->bitmap)) {
642                 mutex_unlock(&drv_data->lock);
643                 return 0;
644         }
645
646         act_ctrl_val = ACT_CTRL_OPCODE_ACTIVATE << ACT_CTRL_OPCODE_SHIFT;
647
648         ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
649                                   DEACTIVATE);
650         if (ret) {
651                 mutex_unlock(&drv_data->lock);
652                 return ret;
653         }
654
655         __set_bit(desc->slice_id, drv_data->bitmap);
656         mutex_unlock(&drv_data->lock);
657
658         return ret;
659 }
660 EXPORT_SYMBOL_GPL(llcc_slice_activate);
661
662 /**
663  * llcc_slice_deactivate - Deactivate the llcc slice
664  * @desc: Pointer to llcc slice descriptor
665  *
666  * A value of zero will be returned on success and a negative errno will
667  * be returned in error cases
668  */
669 int llcc_slice_deactivate(struct llcc_slice_desc *desc)
670 {
671         u32 act_ctrl_val;
672         int ret;
673
674         if (IS_ERR(drv_data))
675                 return PTR_ERR(drv_data);
676
677         if (IS_ERR_OR_NULL(desc))
678                 return -EINVAL;
679
680         mutex_lock(&drv_data->lock);
681         if (!test_bit(desc->slice_id, drv_data->bitmap)) {
682                 mutex_unlock(&drv_data->lock);
683                 return 0;
684         }
685         act_ctrl_val = ACT_CTRL_OPCODE_DEACTIVATE << ACT_CTRL_OPCODE_SHIFT;
686
687         ret = llcc_update_act_ctrl(desc->slice_id, act_ctrl_val,
688                                   ACTIVATE);
689         if (ret) {
690                 mutex_unlock(&drv_data->lock);
691                 return ret;
692         }
693
694         __clear_bit(desc->slice_id, drv_data->bitmap);
695         mutex_unlock(&drv_data->lock);
696
697         return ret;
698 }
699 EXPORT_SYMBOL_GPL(llcc_slice_deactivate);
700
701 /**
702  * llcc_get_slice_id - return the slice id
703  * @desc: Pointer to llcc slice descriptor
704  */
705 int llcc_get_slice_id(struct llcc_slice_desc *desc)
706 {
707         if (IS_ERR_OR_NULL(desc))
708                 return -EINVAL;
709
710         return desc->slice_id;
711 }
712 EXPORT_SYMBOL_GPL(llcc_get_slice_id);
713
714 /**
715  * llcc_get_slice_size - return the slice id
716  * @desc: Pointer to llcc slice descriptor
717  */
718 size_t llcc_get_slice_size(struct llcc_slice_desc *desc)
719 {
720         if (IS_ERR_OR_NULL(desc))
721                 return 0;
722
723         return desc->slice_size;
724 }
725 EXPORT_SYMBOL_GPL(llcc_get_slice_size);
726
727 static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
728                                   const struct qcom_llcc_config *cfg)
729 {
730         int ret;
731         u32 attr2_cfg;
732         u32 attr1_cfg;
733         u32 attr0_cfg;
734         u32 attr2_val;
735         u32 attr1_val;
736         u32 attr0_val;
737         u32 max_cap_cacheline;
738         struct llcc_slice_desc desc;
739
740         attr1_val = config->cache_mode;
741         attr1_val |= config->probe_target_ways << ATTR1_PROBE_TARGET_WAYS_SHIFT;
742         attr1_val |= config->fixed_size << ATTR1_FIXED_SIZE_SHIFT;
743         attr1_val |= config->priority << ATTR1_PRIORITY_SHIFT;
744
745         max_cap_cacheline = MAX_CAP_TO_BYTES(config->max_cap);
746
747         /*
748          * LLCC instances can vary for each target.
749          * The SW writes to broadcast register which gets propagated
750          * to each llcc instance (llcc0,.. llccN).
751          * Since the size of the memory is divided equally amongst the
752          * llcc instances, we need to configure the max cap accordingly.
753          */
754         max_cap_cacheline = max_cap_cacheline / drv_data->num_banks;
755         max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT;
756         attr1_val |= max_cap_cacheline << ATTR1_MAX_CAP_SHIFT;
757
758         attr1_cfg = LLCC_TRP_ATTR1_CFGn(config->slice_id);
759
760         ret = regmap_write(drv_data->bcast_regmap, attr1_cfg, attr1_val);
761         if (ret)
762                 return ret;
763
764         if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
765                 attr2_cfg = LLCC_TRP_ATTR2_CFGn(config->slice_id);
766                 attr0_val = config->res_ways;
767                 attr2_val = config->bonus_ways;
768         } else {
769                 attr0_val = config->res_ways & ATTR0_RES_WAYS_MASK;
770                 attr0_val |= config->bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
771         }
772
773         attr0_cfg = LLCC_TRP_ATTR0_CFGn(config->slice_id);
774
775         ret = regmap_write(drv_data->bcast_regmap, attr0_cfg, attr0_val);
776         if (ret)
777                 return ret;
778
779         if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
780                 ret = regmap_write(drv_data->bcast_regmap, attr2_cfg, attr2_val);
781                 if (ret)
782                         return ret;
783         }
784
785         if (cfg->need_llcc_cfg) {
786                 u32 disable_cap_alloc, retain_pc;
787
788                 disable_cap_alloc = config->dis_cap_alloc << config->slice_id;
789                 ret = regmap_write(drv_data->bcast_regmap,
790                                 LLCC_TRP_SCID_DIS_CAP_ALLOC, disable_cap_alloc);
791                 if (ret)
792                         return ret;
793
794                 if (drv_data->version < LLCC_VERSION_4_1_0_0) {
795                         retain_pc = config->retain_on_pc << config->slice_id;
796                         ret = regmap_write(drv_data->bcast_regmap,
797                                         LLCC_TRP_PCB_ACT, retain_pc);
798                         if (ret)
799                                 return ret;
800                 }
801         }
802
803         if (drv_data->version >= LLCC_VERSION_2_0_0_0) {
804                 u32 wren;
805
806                 wren = config->write_scid_en << config->slice_id;
807                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_WRSC_EN,
808                                          BIT(config->slice_id), wren);
809                 if (ret)
810                         return ret;
811         }
812
813         if (drv_data->version >= LLCC_VERSION_2_1_0_0) {
814                 u32 wr_cache_en;
815
816                 wr_cache_en = config->write_scid_cacheable_en << config->slice_id;
817                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_WRSC_CACHEABLE_EN,
818                                          BIT(config->slice_id), wr_cache_en);
819                 if (ret)
820                         return ret;
821         }
822
823         if (drv_data->version >= LLCC_VERSION_4_1_0_0) {
824                 u32 stale_en;
825                 u32 stale_cap_en;
826                 u32 mru_uncap_en;
827                 u32 mru_rollover;
828                 u32 alloc_oneway_en;
829                 u32 ovcap_en;
830                 u32 ovcap_prio;
831                 u32 vict_prio;
832
833                 stale_en = config->stale_en << config->slice_id;
834                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG1,
835                                          BIT(config->slice_id), stale_en);
836                 if (ret)
837                         return ret;
838
839                 stale_cap_en = config->stale_cap_en << config->slice_id;
840                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG2,
841                                          BIT(config->slice_id), stale_cap_en);
842                 if (ret)
843                         return ret;
844
845                 mru_uncap_en = config->mru_uncap_en << config->slice_id;
846                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG3,
847                                          BIT(config->slice_id), mru_uncap_en);
848                 if (ret)
849                         return ret;
850
851                 mru_rollover = config->mru_rollover << config->slice_id;
852                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG4,
853                                          BIT(config->slice_id), mru_rollover);
854                 if (ret)
855                         return ret;
856
857                 alloc_oneway_en = config->alloc_oneway_en << config->slice_id;
858                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG5,
859                                          BIT(config->slice_id), alloc_oneway_en);
860                 if (ret)
861                         return ret;
862
863                 ovcap_en = config->ovcap_en << config->slice_id;
864                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG6,
865                                          BIT(config->slice_id), ovcap_en);
866                 if (ret)
867                         return ret;
868
869                 ovcap_prio = config->ovcap_prio << config->slice_id;
870                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG7,
871                                          BIT(config->slice_id), ovcap_prio);
872                 if (ret)
873                         return ret;
874
875                 vict_prio = config->vict_prio << config->slice_id;
876                 ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_ALGO_CFG8,
877                                          BIT(config->slice_id), vict_prio);
878                 if (ret)
879                         return ret;
880         }
881
882         if (config->activate_on_init) {
883                 desc.slice_id = config->slice_id;
884                 ret = llcc_slice_activate(&desc);
885         }
886
887         return ret;
888 }
889
890 static int qcom_llcc_cfg_program(struct platform_device *pdev,
891                                  const struct qcom_llcc_config *cfg)
892 {
893         int i;
894         u32 sz;
895         int ret = 0;
896         const struct llcc_slice_config *llcc_table;
897
898         sz = drv_data->cfg_size;
899         llcc_table = drv_data->cfg;
900
901         for (i = 0; i < sz; i++) {
902                 ret = _qcom_llcc_cfg_program(&llcc_table[i], cfg);
903                 if (ret)
904                         return ret;
905         }
906
907         return ret;
908 }
909
910 static int qcom_llcc_remove(struct platform_device *pdev)
911 {
912         /* Set the global pointer to a error code to avoid referencing it */
913         drv_data = ERR_PTR(-ENODEV);
914         return 0;
915 }
916
917 static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, u8 index,
918                                           const char *name)
919 {
920         void __iomem *base;
921         struct regmap_config llcc_regmap_config = {
922                 .reg_bits = 32,
923                 .reg_stride = 4,
924                 .val_bits = 32,
925                 .fast_io = true,
926         };
927
928         base = devm_platform_ioremap_resource(pdev, index);
929         if (IS_ERR(base))
930                 return ERR_CAST(base);
931
932         llcc_regmap_config.name = name;
933         return devm_regmap_init_mmio(&pdev->dev, base, &llcc_regmap_config);
934 }
935
936 static int qcom_llcc_probe(struct platform_device *pdev)
937 {
938         u32 num_banks;
939         struct device *dev = &pdev->dev;
940         int ret, i;
941         struct platform_device *llcc_edac;
942         const struct qcom_llcc_config *cfg;
943         const struct llcc_slice_config *llcc_cfg;
944         u32 sz;
945         u32 version;
946         struct regmap *regmap;
947
948         drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
949         if (!drv_data) {
950                 ret = -ENOMEM;
951                 goto err;
952         }
953
954         /* Initialize the first LLCC bank regmap */
955         regmap = qcom_llcc_init_mmio(pdev, 0, "llcc0_base");
956         if (IS_ERR(regmap)) {
957                 ret = PTR_ERR(regmap);
958                 goto err;
959         }
960
961         cfg = of_device_get_match_data(&pdev->dev);
962
963         ret = regmap_read(regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], &num_banks);
964         if (ret)
965                 goto err;
966
967         num_banks &= LLCC_LB_CNT_MASK;
968         num_banks >>= LLCC_LB_CNT_SHIFT;
969         drv_data->num_banks = num_banks;
970
971         drv_data->regmaps = devm_kcalloc(dev, num_banks, sizeof(*drv_data->regmaps), GFP_KERNEL);
972         if (!drv_data->regmaps) {
973                 ret = -ENOMEM;
974                 goto err;
975         }
976
977         drv_data->regmaps[0] = regmap;
978
979         /* Initialize rest of LLCC bank regmaps */
980         for (i = 1; i < num_banks; i++) {
981                 char *base = kasprintf(GFP_KERNEL, "llcc%d_base", i);
982
983                 drv_data->regmaps[i] = qcom_llcc_init_mmio(pdev, i, base);
984                 if (IS_ERR(drv_data->regmaps[i])) {
985                         ret = PTR_ERR(drv_data->regmaps[i]);
986                         kfree(base);
987                         goto err;
988                 }
989
990                 kfree(base);
991         }
992
993         drv_data->bcast_regmap = qcom_llcc_init_mmio(pdev, i, "llcc_broadcast_base");
994         if (IS_ERR(drv_data->bcast_regmap)) {
995                 ret = PTR_ERR(drv_data->bcast_regmap);
996                 goto err;
997         }
998
999         /* Extract version of the IP */
1000         ret = regmap_read(drv_data->bcast_regmap, cfg->reg_offset[LLCC_COMMON_HW_INFO],
1001                           &version);
1002         if (ret)
1003                 goto err;
1004
1005         drv_data->version = version;
1006
1007         llcc_cfg = cfg->sct_data;
1008         sz = cfg->size;
1009
1010         for (i = 0; i < sz; i++)
1011                 if (llcc_cfg[i].slice_id > drv_data->max_slices)
1012                         drv_data->max_slices = llcc_cfg[i].slice_id;
1013
1014         drv_data->bitmap = devm_bitmap_zalloc(dev, drv_data->max_slices,
1015                                               GFP_KERNEL);
1016         if (!drv_data->bitmap) {
1017                 ret = -ENOMEM;
1018                 goto err;
1019         }
1020
1021         drv_data->cfg = llcc_cfg;
1022         drv_data->cfg_size = sz;
1023         drv_data->edac_reg_offset = cfg->edac_reg_offset;
1024         mutex_init(&drv_data->lock);
1025         platform_set_drvdata(pdev, drv_data);
1026
1027         ret = qcom_llcc_cfg_program(pdev, cfg);
1028         if (ret)
1029                 goto err;
1030
1031         drv_data->ecc_irq = platform_get_irq_optional(pdev, 0);
1032
1033         /*
1034          * On some platforms, the access to EDAC registers will be locked by
1035          * the bootloader. So probing the EDAC driver will result in a crash.
1036          * Hence, disable the creation of EDAC platform device for the
1037          * problematic platforms.
1038          */
1039         if (!cfg->no_edac) {
1040                 llcc_edac = platform_device_register_data(&pdev->dev,
1041                                                 "qcom_llcc_edac", -1, drv_data,
1042                                                 sizeof(*drv_data));
1043                 if (IS_ERR(llcc_edac))
1044                         dev_err(dev, "Failed to register llcc edac driver\n");
1045         }
1046
1047         return 0;
1048 err:
1049         drv_data = ERR_PTR(-ENODEV);
1050         return ret;
1051 }
1052
1053 static const struct of_device_id qcom_llcc_of_match[] = {
1054         { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg },
1055         { .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfg },
1056         { .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfg },
1057         { .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfg },
1058         { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg },
1059         { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg },
1060         { .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfg },
1061         { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg },
1062         { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg },
1063         { .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg },
1064         { .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfg },
1065         { .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfg },
1066         { }
1067 };
1068 MODULE_DEVICE_TABLE(of, qcom_llcc_of_match);
1069
1070 static struct platform_driver qcom_llcc_driver = {
1071         .driver = {
1072                 .name = "qcom-llcc",
1073                 .of_match_table = qcom_llcc_of_match,
1074         },
1075         .probe = qcom_llcc_probe,
1076         .remove = qcom_llcc_remove,
1077 };
1078 module_platform_driver(qcom_llcc_driver);
1079
1080 MODULE_DESCRIPTION("Qualcomm Last Level Cache Controller");
1081 MODULE_LICENSE("GPL v2");
This page took 0.09687 seconds and 4 git commands to generate.