Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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 */
 21static 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 */
 42static 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 */
 56static 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 */
 74static 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 */
 89static 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 */
103void 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 */
138static 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 */
192static 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 */
226static 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 */
256int 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
269void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev)
270{
271	cscfg_prog_config(config_csdev, false);
272}