linux/drivers/hwtracing/coresight/coresight-config.c
<<
>>
Prefs
   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}
 273