1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright(C) 2020 Linaro Limited. All rights reserved.
4 * Author: Mike Leach <mike.leach@linaro.org>
7 #include <linux/sysfs.h>
8 #include "coresight-config.h"
9 #include "coresight-priv.h"
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.
18 * Write the value held in the register structure into the driver internal memory
21 static void cscfg_set_reg(struct cscfg_regval_csdev
*reg_csdev
)
23 u32
*p_val32
= (u32
*)reg_csdev
->driver_regval
;
24 u32 tmp32
= reg_csdev
->reg_desc
.val32
;
26 if (reg_csdev
->reg_desc
.type
& CS_CFG_REG_TYPE_VAL_64BIT
) {
27 *((u64
*)reg_csdev
->driver_regval
) = reg_csdev
->reg_desc
.val64
;
31 if (reg_csdev
->reg_desc
.type
& CS_CFG_REG_TYPE_VAL_MASK
) {
33 tmp32
&= ~reg_csdev
->reg_desc
.mask32
;
34 tmp32
|= reg_csdev
->reg_desc
.val32
& reg_csdev
->reg_desc
.mask32
;
40 * Read the driver value into the reg if this is marked as one we want to save.
42 static void cscfg_save_reg(struct cscfg_regval_csdev
*reg_csdev
)
44 if (!(reg_csdev
->reg_desc
.type
& CS_CFG_REG_TYPE_VAL_SAVE
))
46 if (reg_csdev
->reg_desc
.type
& CS_CFG_REG_TYPE_VAL_64BIT
)
47 reg_csdev
->reg_desc
.val64
= *(u64
*)(reg_csdev
->driver_regval
);
49 reg_csdev
->reg_desc
.val32
= *(u32
*)(reg_csdev
->driver_regval
);
53 * Some register values are set from parameters. Initialise these registers
54 * from the current parameter values.
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
)
60 struct cscfg_parameter_csdev
*param_csdev
;
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
;
67 if (param_csdev
->val64
)
68 reg_csdev
->reg_desc
.val64
= param_csdev
->current_value
;
70 reg_csdev
->reg_desc
.val32
= (u32
)param_csdev
->current_value
;
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
)
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");
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
)
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");
102 /* default reset - restore default values */
103 void cscfg_reset_feat(struct cscfg_feature_csdev
*feat_csdev
)
105 struct cscfg_regval_desc
*reg_desc
;
106 struct cscfg_regval_csdev
*reg_csdev
;
110 * set the default values for all parameters and regs from the
111 * relevant static descriptors.
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
;
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
;
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
);
127 * for normal values the union between val64 & val32 + mask32
128 * allows us to init using the 64 bit value
130 reg_csdev
->reg_desc
.val64
= reg_desc
->val64
;
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.
138 static int cscfg_update_presets(struct cscfg_config_csdev
*config_csdev
, int preset
)
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
;
145 const u64
*preset_base
;
148 /* preset in range 1 to nr_presets */
149 if (preset
< 1 || preset
> config_desc
->nr_presets
)
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.
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
)
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
;
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
);
180 /* exit early if all params filled */
181 if (val_idx
>= nr_cfg_params
)
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.
192 static int cscfg_update_curr_params(struct cscfg_config_csdev
*config_csdev
)
195 struct cscfg_feature_csdev
*feat_csdev
;
196 struct cscfg_parameter_csdev
*param_csdev
;
200 for (i
= 0; i
< config_csdev
->nr_feat
; i
++) {
201 feat_csdev
= config_csdev
->feats_csdev
[i
];
202 if (!feat_csdev
->nr_params
)
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
;
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
);
223 * Configuration values will be programmed into the driver locations if enabling, or read
224 * from relevant locations on disable.
226 static int cscfg_prog_config(struct cscfg_config_csdev
*config_csdev
, bool enable
)
229 struct cscfg_feature_csdev
*feat_csdev
;
230 struct coresight_device
*csdev
;
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
);
239 err
= cscfg_set_on_enable(feat_csdev
);
241 cscfg_save_on_disable(feat_csdev
);
250 * Enable configuration for the device. Will result in the internal driver data
251 * being updated ready for programming into the device.
253 * @config_csdev: config_csdev to set.
254 * @preset: preset values to use - 0 for default.
256 int cscfg_csdev_enable_config(struct cscfg_config_csdev
*config_csdev
, int preset
)
261 err
= cscfg_update_presets(config_csdev
, preset
);
263 err
= cscfg_update_curr_params(config_csdev
);
265 err
= cscfg_prog_config(config_csdev
, true);
269 void cscfg_csdev_disable_config(struct cscfg_config_csdev
*config_csdev
)
271 cscfg_prog_config(config_csdev
, false);