brintos

brintos / linux-shallow public Read only

0
0
Text · 8.1 KiB · 4723bf7 Raw
273 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 configurations13 * and features to manage the handling of parameters, the programming and14 * saving of registers used by features on devices.15 */16 17/*18 * Write the value held in the register structure into the driver internal memory19 * 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	else49		reg_csdev->reg_desc.val32 = *(u32 *)(reg_csdev->driver_regval);50}51 52/*53 * Some register values are set from parameters. Initialise these registers54 * 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	else70		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 the111	 * 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		else126			/*127			 * for normal values the union between val64 & val32 + mask32128			 * allows us to init using the 64 bit value129			 */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, to136 * 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 to153	 * feature parameters in the order they appear.154	 * There should be precisely the same number of preset values as the155	 * sum of number of parameters over all the features - but we will156	 * 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 params189 * with current values. This sets the register associated with the parameter190 * 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 read224 * 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		else241			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 data251 * 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	else263		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}273