Unverified Commit dc65b1ed authored by Sheetal's avatar Sheetal Committed by Mark Brown
Browse files

regmap: Add reg_default_cb callback for flat cache defaults



Commit e062bdfd ("regmap: warn users about uninitialized flat cache")
warns when REGCACHE_FLAT is used without full defaults. This causes
false positives on hardware where many registers reset to zero but are
not listed in reg_defaults, forcing drivers to maintain large tables
just to silence the warning.

Add a reg_default_cb() hook so drivers can supply defaults for registers
not present in reg_defaults when populating REGCACHE_FLAT. This keeps
the warning quiet for known zero-reset registers without bloating
tables. Provide a generic regmap_default_zero_cb() helper for drivers
that need zero defaults.

The hook is only used for REGCACHE_FLAT; the core does not
check readable/writeable access, so drivers must provide readable_reg/
writeable_reg callbacks and handle holes in the register map.

Signed-off-by: default avatarSheetal <sheetal@nvidia.com>
Link: https://patch.msgid.link/20260123095346.1258556-3-sheetal@nvidia.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 63804fed
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -117,6 +117,9 @@ struct regmap {
		    void *val_buf, size_t val_size);
	int (*write)(void *context, const void *data, size_t count);

	int (*reg_default_cb)(struct device *dev, unsigned int reg,
			      unsigned int *val);

	unsigned long read_flag_mask;
	unsigned long write_flag_mask;

+19 −0
Original line number Diff line number Diff line
@@ -79,6 +79,25 @@ static int regcache_flat_populate(struct regmap *map)
		__set_bit(index, cache->valid);
	}

	if (map->reg_default_cb) {
		dev_dbg(map->dev,
			"Populating regcache_flat using reg_default_cb callback\n");

		for (i = 0; i <= map->max_register; i += map->reg_stride) {
			unsigned int index = regcache_flat_get_index(map, i);
			unsigned int value;

			if (test_bit(index, cache->valid))
				continue;

			if (map->reg_default_cb(map->dev, i, &value))
				continue;

			cache->data[index] = value;
			__set_bit(index, cache->valid);
		}
	}

	return 0;
}

+2 −1
Original line number Diff line number Diff line
@@ -223,7 +223,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
			goto err_free;
	}

	if (map->num_reg_defaults && map->cache_ops->populate) {
	if (map->cache_ops->populate &&
	    (map->num_reg_defaults || map->reg_default_cb)) {
		dev_dbg(map->dev, "Populating %s cache\n", map->cache_ops->name);
		map->lock(map->lock_arg);
		ret = map->cache_ops->populate(map);
+2 −0
Original line number Diff line number Diff line
@@ -813,6 +813,7 @@ struct regmap *__regmap_init(struct device *dev,
	map->precious_reg = config->precious_reg;
	map->writeable_noinc_reg = config->writeable_noinc_reg;
	map->readable_noinc_reg = config->readable_noinc_reg;
	map->reg_default_cb = config->reg_default_cb;
	map->cache_type = config->cache_type;

	spin_lock_init(&map->async_lock);
@@ -1435,6 +1436,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
	map->precious_reg = config->precious_reg;
	map->writeable_noinc_reg = config->writeable_noinc_reg;
	map->readable_noinc_reg = config->readable_noinc_reg;
	map->reg_default_cb = config->reg_default_cb;
	map->cache_type = config->cache_type;

	ret = regmap_set_name(map, config);
+14 −0
Original line number Diff line number Diff line
@@ -359,6 +359,10 @@ typedef void (*regmap_unlock)(void *);
 * @reg_defaults: Power on reset values for registers (for use with
 *                register cache support).
 * @num_reg_defaults: Number of elements in reg_defaults.
 * @reg_default_cb: Optional callback to return default values for registers
 *                  not listed in reg_defaults. This is only used for
 *                  REGCACHE_FLAT population; drivers must ensure the readable_reg/
 *                  writeable_reg callbacks are defined to handle holes.
 *
 * @read_flag_mask: Mask to be set in the top bytes of the register when doing
 *                  a read.
@@ -449,6 +453,8 @@ struct regmap_config {
	const struct regmap_access_table *rd_noinc_table;
	const struct reg_default *reg_defaults;
	unsigned int num_reg_defaults;
	int (*reg_default_cb)(struct device *dev, unsigned int reg,
			      unsigned int *def);
	enum regcache_type cache_type;
	const void *reg_defaults_raw;
	unsigned int num_reg_defaults_raw;
@@ -1349,6 +1355,14 @@ static inline int regmap_write_bits(struct regmap *map, unsigned int reg,
	return regmap_update_bits_base(map, reg, mask, val, NULL, false, true);
}

static inline int regmap_default_zero_cb(struct device *dev,
					 unsigned int reg,
					 unsigned int *def)
{
	*def = 0;
	return 0;
}

int regmap_get_val_bytes(struct regmap *map);
int regmap_get_max_register(struct regmap *map);
int regmap_get_reg_stride(struct regmap *map);