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 } 273