GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / hwtracing / coresight / coresight-config.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright(C) 2020 Linaro Limited. All rights reserved.
4  * Author: Mike Leach <mike.leach@linaro.org>
5  */
6
7 #include <linux/sysfs.h>
8 #include "coresight-config.h"
9 #include "coresight-priv.h"
10
11 /*
12  * This provides a set of generic functions that operate on configurations
13  * and features to manage the handling of parameters, the programming and
14  * saving of registers used by features on devices.
15  */
16
17 /*
18  * Write the value held in the register structure into the driver internal memory
19  * location.
20  */
21 static void cscfg_set_reg(struct cscfg_regval_csdev *reg_csdev)
22 {
23         u32 *p_val32 = (u32 *)reg_csdev->driver_regval;
24         u32 tmp32 = reg_csdev->reg_desc.val32;
25
26         if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT) {
27                 *((u64 *)reg_csdev->driver_regval) = reg_csdev->reg_desc.val64;
28                 return;
29         }
30
31         if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_MASK) {
32                 tmp32 = *p_val32;
33                 tmp32 &= ~reg_csdev->reg_desc.mask32;
34                 tmp32 |= reg_csdev->reg_desc.val32 & reg_csdev->reg_desc.mask32;
35         }
36         *p_val32 = tmp32;
37 }
38
39 /*
40  * Read the driver value into the reg if this is marked as one we want to save.
41  */
42 static void cscfg_save_reg(struct cscfg_regval_csdev *reg_csdev)
43 {
44         if (!(reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_SAVE))
45                 return;
46         if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT)
47                 reg_csdev->reg_desc.val64 = *(u64 *)(reg_csdev->driver_regval);
48         else
49                 reg_csdev->reg_desc.val32 = *(u32 *)(reg_csdev->driver_regval);
50 }
51
52 /*
53  * Some register values are set from parameters. Initialise these registers
54  * from the current parameter values.
55  */
56 static void cscfg_init_reg_param(struct cscfg_feature_csdev *feat_csdev,
57                                  struct cscfg_regval_desc *reg_desc,
58                                  struct cscfg_regval_csdev *reg_csdev)
59 {
60         struct cscfg_parameter_csdev *param_csdev;
61
62         /* for param, load routines have validated the index */
63         param_csdev = &feat_csdev->params_csdev[reg_desc->param_idx];
64         param_csdev->reg_csdev = reg_csdev;
65         param_csdev->val64 = reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT;
66
67         if (param_csdev->val64)
68                 reg_csdev->reg_desc.val64 = param_csdev->current_value;
69         else
70                 reg_csdev->reg_desc.val32 = (u32)param_csdev->current_value;
71 }
72
73 /* set values into the driver locations referenced in cscfg_reg_csdev */
74 static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat_csdev)
75 {
76         unsigned long flags;
77         int i;
78
79         spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
80         for (i = 0; i < feat_csdev->nr_regs; i++)
81                 cscfg_set_reg(&feat_csdev->regs_csdev[i]);
82         spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
83         dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s",
84                 feat_csdev->feat_desc->name, "set on enable");
85         return 0;
86 }
87
88 /* copy back values from the driver locations referenced in cscfg_reg_csdev */
89 static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat_csdev)
90 {
91         unsigned long flags;
92         int i;
93
94         spin_lock_irqsave(feat_csdev->drv_spinlock, flags);
95         for (i = 0; i < feat_csdev->nr_regs; i++)
96                 cscfg_save_reg(&feat_csdev->regs_csdev[i]);
97         spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags);
98         dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s",
99                 feat_csdev->feat_desc->name, "save on disable");
100 }
101
102 /* default reset - restore default values */
103 void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev)
104 {
105         struct cscfg_regval_desc *reg_desc;
106         struct cscfg_regval_csdev *reg_csdev;
107         int i;
108
109         /*
110          * set the default values for all parameters and regs from the
111          * relevant static descriptors.
112          */
113         for (i = 0; i < feat_csdev->nr_params; i++)
114                 feat_csdev->params_csdev[i].current_value =
115                         feat_csdev->feat_desc->params_desc[i].value;
116
117         for (i = 0; i < feat_csdev->nr_regs; i++) {
118                 reg_desc = &feat_csdev->feat_desc->regs_desc[i];
119                 reg_csdev = &feat_csdev->regs_csdev[i];
120                 reg_csdev->reg_desc.type = reg_desc->type;
121
122                 /* check if reg set from a parameter otherwise desc default */
123                 if (reg_desc->type & CS_CFG_REG_TYPE_VAL_PARAM)
124                         cscfg_init_reg_param(feat_csdev, reg_desc, reg_csdev);
125                 else
126                         /*
127                          * for normal values the union between val64 & val32 + mask32
128                          * allows us to init using the 64 bit value
129                          */
130                         reg_csdev->reg_desc.val64 = reg_desc->val64;
131         }
132 }
133
134 /*
135  * For the selected presets, we set the register associated with the parameter, to
136  * the value of the preset index associated with the parameter.
137  */
138 static int cscfg_update_presets(struct cscfg_config_csdev *config_csdev, int preset)
139 {
140         int i, j, val_idx = 0, nr_cfg_params;
141         struct cscfg_parameter_csdev *param_csdev;
142         struct cscfg_feature_csdev *feat_csdev;
143         const struct cscfg_config_desc *config_desc = config_csdev->config_desc;
144         const char *name;
145         const u64 *preset_base;
146         u64 val;
147
148         /* preset in range 1 to nr_presets */
149         if (preset < 1 || preset > config_desc->nr_presets)
150                 return -EINVAL;
151         /*
152          * Go through the array of features, assigning preset values to
153          * feature parameters in the order they appear.
154          * There should be precisely the same number of preset values as the
155          * sum of number of parameters over all the features - but we will
156          * ensure there is no overrun.
157          */
158         nr_cfg_params = config_desc->nr_total_params;
159         preset_base = &config_desc->presets[(preset - 1) * nr_cfg_params];
160         for (i = 0; i < config_csdev->nr_feat; i++) {
161                 feat_csdev = config_csdev->feats_csdev[i];
162                 if (!feat_csdev->nr_params)
163                         continue;
164
165                 for (j = 0; j < feat_csdev->nr_params; j++) {
166                         param_csdev = &feat_csdev->params_csdev[j];
167                         name = feat_csdev->feat_desc->params_desc[j].name;
168                         val = preset_base[val_idx++];
169                         if (param_csdev->val64) {
170                                 dev_dbg(&config_csdev->csdev->dev,
171                                         "set param %s (%lld)", name, val);
172                                 param_csdev->reg_csdev->reg_desc.val64 = val;
173                         } else {
174                                 param_csdev->reg_csdev->reg_desc.val32 = (u32)val;
175                                 dev_dbg(&config_csdev->csdev->dev,
176                                         "set param %s (%d)", name, (u32)val);
177                         }
178                 }
179
180                 /* exit early if all params filled */
181                 if (val_idx >= nr_cfg_params)
182                         break;
183         }
184         return 0;
185 }
186
187 /*
188  * if we are not using a preset, then need to update the feature params
189  * with current values. This sets the register associated with the parameter
190  * with the current value of that parameter.
191  */
192 static int cscfg_update_curr_params(struct cscfg_config_csdev *config_csdev)
193 {
194         int i, j;
195         struct cscfg_feature_csdev *feat_csdev;
196         struct cscfg_parameter_csdev *param_csdev;
197         const char *name;
198         u64 val;
199
200         for (i = 0; i < config_csdev->nr_feat; i++) {
201                 feat_csdev = config_csdev->feats_csdev[i];
202                 if (!feat_csdev->nr_params)
203                         continue;
204                 for (j = 0; j < feat_csdev->nr_params; j++) {
205                         param_csdev = &feat_csdev->params_csdev[j];
206                         name = feat_csdev->feat_desc->params_desc[j].name;
207                         val = param_csdev->current_value;
208                         if (param_csdev->val64) {
209                                 dev_dbg(&config_csdev->csdev->dev,
210                                         "set param %s (%lld)", name, val);
211                                 param_csdev->reg_csdev->reg_desc.val64 = val;
212                         } else {
213                                 param_csdev->reg_csdev->reg_desc.val32 = (u32)val;
214                                 dev_dbg(&config_csdev->csdev->dev,
215                                         "set param %s (%d)", name, (u32)val);
216                         }
217                 }
218         }
219         return 0;
220 }
221
222 /*
223  * Configuration values will be programmed into the driver locations if enabling, or read
224  * from relevant locations on disable.
225  */
226 static int cscfg_prog_config(struct cscfg_config_csdev *config_csdev, bool enable)
227 {
228         int i, err = 0;
229         struct cscfg_feature_csdev *feat_csdev;
230         struct coresight_device *csdev;
231
232         for (i = 0; i < config_csdev->nr_feat; i++) {
233                 feat_csdev = config_csdev->feats_csdev[i];
234                 csdev = feat_csdev->csdev;
235                 dev_dbg(&csdev->dev, "cfg %s;  %s feature:%s", config_csdev->config_desc->name,
236                         enable ? "enable" : "disable", feat_csdev->feat_desc->name);
237
238                 if (enable)
239                         err = cscfg_set_on_enable(feat_csdev);
240                 else
241                         cscfg_save_on_disable(feat_csdev);
242
243                 if (err)
244                         break;
245         }
246         return err;
247 }
248
249 /*
250  * Enable configuration for the device. Will result in the internal driver data
251  * being updated ready for programming into the device.
252  *
253  * @config_csdev:       config_csdev to set.
254  * @preset:             preset values to use - 0 for default.
255  */
256 int cscfg_csdev_enable_config(struct cscfg_config_csdev *config_csdev, int preset)
257 {
258         int err = 0;
259
260         if (preset)
261                 err = cscfg_update_presets(config_csdev, preset);
262         else
263                 err = cscfg_update_curr_params(config_csdev);
264         if (!err)
265                 err = cscfg_prog_config(config_csdev, true);
266         return err;
267 }
268
269 void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev)
270 {
271         cscfg_prog_config(config_csdev, false);
272 }