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