162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// regmap KUnit tests
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Copyright 2023 Arm Ltd
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <kunit/test.h>
862306a36Sopenharmony_ci#include "internal.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define BLOCK_TEST_SIZE 12
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_cistatic void get_changed_bytes(void *orig, void *new, size_t size)
1362306a36Sopenharmony_ci{
1462306a36Sopenharmony_ci	char *o = orig;
1562306a36Sopenharmony_ci	char *n = new;
1662306a36Sopenharmony_ci	int i;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	get_random_bytes(new, size);
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	/*
2162306a36Sopenharmony_ci	 * This could be nicer and more efficient but we shouldn't
2262306a36Sopenharmony_ci	 * super care.
2362306a36Sopenharmony_ci	 */
2462306a36Sopenharmony_ci	for (i = 0; i < size; i++)
2562306a36Sopenharmony_ci		while (n[i] == o[i])
2662306a36Sopenharmony_ci			get_random_bytes(&n[i], 1);
2762306a36Sopenharmony_ci}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic const struct regmap_config test_regmap_config = {
3062306a36Sopenharmony_ci	.max_register = BLOCK_TEST_SIZE,
3162306a36Sopenharmony_ci	.reg_stride = 1,
3262306a36Sopenharmony_ci	.val_bits = sizeof(unsigned int) * 8,
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistruct regcache_types {
3662306a36Sopenharmony_ci	enum regcache_type type;
3762306a36Sopenharmony_ci	const char *name;
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic void case_to_desc(const struct regcache_types *t, char *desc)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	strcpy(desc, t->name);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic const struct regcache_types regcache_types_list[] = {
4662306a36Sopenharmony_ci	{ REGCACHE_NONE, "none" },
4762306a36Sopenharmony_ci	{ REGCACHE_FLAT, "flat" },
4862306a36Sopenharmony_ci	{ REGCACHE_RBTREE, "rbtree" },
4962306a36Sopenharmony_ci	{ REGCACHE_MAPLE, "maple" },
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(regcache_types, regcache_types_list, case_to_desc);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic const struct regcache_types real_cache_types_list[] = {
5562306a36Sopenharmony_ci	{ REGCACHE_FLAT, "flat" },
5662306a36Sopenharmony_ci	{ REGCACHE_RBTREE, "rbtree" },
5762306a36Sopenharmony_ci	{ REGCACHE_MAPLE, "maple" },
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(real_cache_types, real_cache_types_list, case_to_desc);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic const struct regcache_types sparse_cache_types_list[] = {
6362306a36Sopenharmony_ci	{ REGCACHE_RBTREE, "rbtree" },
6462306a36Sopenharmony_ci	{ REGCACHE_MAPLE, "maple" },
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(sparse_cache_types, sparse_cache_types_list, case_to_desc);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic struct regmap *gen_regmap(struct regmap_config *config,
7062306a36Sopenharmony_ci				 struct regmap_ram_data **data)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	unsigned int *buf;
7362306a36Sopenharmony_ci	struct regmap *ret;
7462306a36Sopenharmony_ci	size_t size = (config->max_register + 1) * sizeof(unsigned int);
7562306a36Sopenharmony_ci	int i;
7662306a36Sopenharmony_ci	struct reg_default *defaults;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	config->disable_locking = config->cache_type == REGCACHE_RBTREE ||
7962306a36Sopenharmony_ci					config->cache_type == REGCACHE_MAPLE;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	buf = kmalloc(size, GFP_KERNEL);
8262306a36Sopenharmony_ci	if (!buf)
8362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	get_random_bytes(buf, size);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	*data = kzalloc(sizeof(**data), GFP_KERNEL);
8862306a36Sopenharmony_ci	if (!(*data))
8962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
9062306a36Sopenharmony_ci	(*data)->vals = buf;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (config->num_reg_defaults) {
9362306a36Sopenharmony_ci		defaults = kcalloc(config->num_reg_defaults,
9462306a36Sopenharmony_ci				   sizeof(struct reg_default),
9562306a36Sopenharmony_ci				   GFP_KERNEL);
9662306a36Sopenharmony_ci		if (!defaults)
9762306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
9862306a36Sopenharmony_ci		config->reg_defaults = defaults;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		for (i = 0; i < config->num_reg_defaults; i++) {
10162306a36Sopenharmony_ci			defaults[i].reg = i * config->reg_stride;
10262306a36Sopenharmony_ci			defaults[i].def = buf[i * config->reg_stride];
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	ret = regmap_init_ram(config, *data);
10762306a36Sopenharmony_ci	if (IS_ERR(ret)) {
10862306a36Sopenharmony_ci		kfree(buf);
10962306a36Sopenharmony_ci		kfree(*data);
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return ret;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic bool reg_5_false(struct device *context, unsigned int reg)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	return reg != 5;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void basic_read_write(struct kunit *test)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
12362306a36Sopenharmony_ci	struct regmap *map;
12462306a36Sopenharmony_ci	struct regmap_config config;
12562306a36Sopenharmony_ci	struct regmap_ram_data *data;
12662306a36Sopenharmony_ci	unsigned int val, rval;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	config = test_regmap_config;
12962306a36Sopenharmony_ci	config.cache_type = t->type;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
13262306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
13362306a36Sopenharmony_ci	if (IS_ERR(map))
13462306a36Sopenharmony_ci		return;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* If we write a value to a register we can read it back */
13962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 0, val));
14062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 0, &rval));
14162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, val, rval);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	/* If using a cache the cache satisfied the read */
14462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[0]);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	regmap_exit(map);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic void bulk_write(struct kunit *test)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
15262306a36Sopenharmony_ci	struct regmap *map;
15362306a36Sopenharmony_ci	struct regmap_config config;
15462306a36Sopenharmony_ci	struct regmap_ram_data *data;
15562306a36Sopenharmony_ci	unsigned int val[BLOCK_TEST_SIZE], rval[BLOCK_TEST_SIZE];
15662306a36Sopenharmony_ci	int i;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	config = test_regmap_config;
15962306a36Sopenharmony_ci	config.cache_type = t->type;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
16262306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
16362306a36Sopenharmony_ci	if (IS_ERR(map))
16462306a36Sopenharmony_ci		return;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	/*
16962306a36Sopenharmony_ci	 * Data written via the bulk API can be read back with single
17062306a36Sopenharmony_ci	 * reads.
17162306a36Sopenharmony_ci	 */
17262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_bulk_write(map, 0, val,
17362306a36Sopenharmony_ci						   BLOCK_TEST_SIZE));
17462306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
17562306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &rval[i]));
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	KUNIT_EXPECT_MEMEQ(test, val, rval, sizeof(val));
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* If using a cache the cache satisfied the read */
18062306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
18162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	regmap_exit(map);
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic void bulk_read(struct kunit *test)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
18962306a36Sopenharmony_ci	struct regmap *map;
19062306a36Sopenharmony_ci	struct regmap_config config;
19162306a36Sopenharmony_ci	struct regmap_ram_data *data;
19262306a36Sopenharmony_ci	unsigned int val[BLOCK_TEST_SIZE], rval[BLOCK_TEST_SIZE];
19362306a36Sopenharmony_ci	int i;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	config = test_regmap_config;
19662306a36Sopenharmony_ci	config.cache_type = t->type;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
19962306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
20062306a36Sopenharmony_ci	if (IS_ERR(map))
20162306a36Sopenharmony_ci		return;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* Data written as single writes can be read via the bulk API */
20662306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
20762306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, val[i]));
20862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval,
20962306a36Sopenharmony_ci						  BLOCK_TEST_SIZE));
21062306a36Sopenharmony_ci	KUNIT_EXPECT_MEMEQ(test, val, rval, sizeof(val));
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* If using a cache the cache satisfied the read */
21362306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
21462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	regmap_exit(map);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic void write_readonly(struct kunit *test)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
22262306a36Sopenharmony_ci	struct regmap *map;
22362306a36Sopenharmony_ci	struct regmap_config config;
22462306a36Sopenharmony_ci	struct regmap_ram_data *data;
22562306a36Sopenharmony_ci	unsigned int val;
22662306a36Sopenharmony_ci	int i;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	config = test_regmap_config;
22962306a36Sopenharmony_ci	config.cache_type = t->type;
23062306a36Sopenharmony_ci	config.num_reg_defaults = BLOCK_TEST_SIZE;
23162306a36Sopenharmony_ci	config.writeable_reg = reg_5_false;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
23462306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
23562306a36Sopenharmony_ci	if (IS_ERR(map))
23662306a36Sopenharmony_ci		return;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
24162306a36Sopenharmony_ci		data->written[i] = false;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/* Change the value of all registers, readonly should fail */
24462306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
24562306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, i != 5, regmap_write(map, i, val) == 0);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* Did that match what we see on the device? */
24862306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
24962306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, i != 5, data->written[i]);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	regmap_exit(map);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic void read_writeonly(struct kunit *test)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
25762306a36Sopenharmony_ci	struct regmap *map;
25862306a36Sopenharmony_ci	struct regmap_config config;
25962306a36Sopenharmony_ci	struct regmap_ram_data *data;
26062306a36Sopenharmony_ci	unsigned int val;
26162306a36Sopenharmony_ci	int i;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	config = test_regmap_config;
26462306a36Sopenharmony_ci	config.cache_type = t->type;
26562306a36Sopenharmony_ci	config.readable_reg = reg_5_false;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
26862306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
26962306a36Sopenharmony_ci	if (IS_ERR(map))
27062306a36Sopenharmony_ci		return;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
27362306a36Sopenharmony_ci		data->read[i] = false;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/*
27662306a36Sopenharmony_ci	 * Try to read all the registers, the writeonly one should
27762306a36Sopenharmony_ci	 * fail if we aren't using the flat cache.
27862306a36Sopenharmony_ci	 */
27962306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++) {
28062306a36Sopenharmony_ci		if (t->type != REGCACHE_FLAT) {
28162306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, i != 5,
28262306a36Sopenharmony_ci					regmap_read(map, i, &val) == 0);
28362306a36Sopenharmony_ci		} else {
28462306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &val));
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* Did we trigger a hardware access? */
28962306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE(test, data->read[5]);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	regmap_exit(map);
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic void reg_defaults(struct kunit *test)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
29762306a36Sopenharmony_ci	struct regmap *map;
29862306a36Sopenharmony_ci	struct regmap_config config;
29962306a36Sopenharmony_ci	struct regmap_ram_data *data;
30062306a36Sopenharmony_ci	unsigned int rval[BLOCK_TEST_SIZE];
30162306a36Sopenharmony_ci	int i;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	config = test_regmap_config;
30462306a36Sopenharmony_ci	config.cache_type = t->type;
30562306a36Sopenharmony_ci	config.num_reg_defaults = BLOCK_TEST_SIZE;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
30862306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
30962306a36Sopenharmony_ci	if (IS_ERR(map))
31062306a36Sopenharmony_ci		return;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/* Read back the expected default data */
31362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval,
31462306a36Sopenharmony_ci						  BLOCK_TEST_SIZE));
31562306a36Sopenharmony_ci	KUNIT_EXPECT_MEMEQ(test, data->vals, rval, sizeof(rval));
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* The data should have been read from cache if there was one */
31862306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
31962306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]);
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic void reg_defaults_read_dev(struct kunit *test)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
32562306a36Sopenharmony_ci	struct regmap *map;
32662306a36Sopenharmony_ci	struct regmap_config config;
32762306a36Sopenharmony_ci	struct regmap_ram_data *data;
32862306a36Sopenharmony_ci	unsigned int rval[BLOCK_TEST_SIZE];
32962306a36Sopenharmony_ci	int i;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	config = test_regmap_config;
33262306a36Sopenharmony_ci	config.cache_type = t->type;
33362306a36Sopenharmony_ci	config.num_reg_defaults_raw = BLOCK_TEST_SIZE;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
33662306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
33762306a36Sopenharmony_ci	if (IS_ERR(map))
33862306a36Sopenharmony_ci		return;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* We should have read the cache defaults back from the map */
34162306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++) {
34262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, t->type != REGCACHE_NONE, data->read[i]);
34362306a36Sopenharmony_ci		data->read[i] = false;
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	/* Read back the expected default data */
34762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval,
34862306a36Sopenharmony_ci						  BLOCK_TEST_SIZE));
34962306a36Sopenharmony_ci	KUNIT_EXPECT_MEMEQ(test, data->vals, rval, sizeof(rval));
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	/* The data should have been read from cache if there was one */
35262306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
35362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void register_patch(struct kunit *test)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
35962306a36Sopenharmony_ci	struct regmap *map;
36062306a36Sopenharmony_ci	struct regmap_config config;
36162306a36Sopenharmony_ci	struct regmap_ram_data *data;
36262306a36Sopenharmony_ci	struct reg_sequence patch[2];
36362306a36Sopenharmony_ci	unsigned int rval[BLOCK_TEST_SIZE];
36462306a36Sopenharmony_ci	int i;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* We need defaults so readback works */
36762306a36Sopenharmony_ci	config = test_regmap_config;
36862306a36Sopenharmony_ci	config.cache_type = t->type;
36962306a36Sopenharmony_ci	config.num_reg_defaults = BLOCK_TEST_SIZE;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
37262306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
37362306a36Sopenharmony_ci	if (IS_ERR(map))
37462306a36Sopenharmony_ci		return;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	/* Stash the original values */
37762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval,
37862306a36Sopenharmony_ci						  BLOCK_TEST_SIZE));
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	/* Patch a couple of values */
38162306a36Sopenharmony_ci	patch[0].reg = 2;
38262306a36Sopenharmony_ci	patch[0].def = rval[2] + 1;
38362306a36Sopenharmony_ci	patch[0].delay_us = 0;
38462306a36Sopenharmony_ci	patch[1].reg = 5;
38562306a36Sopenharmony_ci	patch[1].def = rval[5] + 1;
38662306a36Sopenharmony_ci	patch[1].delay_us = 0;
38762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_register_patch(map, patch,
38862306a36Sopenharmony_ci						       ARRAY_SIZE(patch)));
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	/* Only the patched registers are written */
39162306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++) {
39262306a36Sopenharmony_ci		switch (i) {
39362306a36Sopenharmony_ci		case 2:
39462306a36Sopenharmony_ci		case 5:
39562306a36Sopenharmony_ci			KUNIT_EXPECT_TRUE(test, data->written[i]);
39662306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, data->vals[i], rval[i] + 1);
39762306a36Sopenharmony_ci			break;
39862306a36Sopenharmony_ci		default:
39962306a36Sopenharmony_ci			KUNIT_EXPECT_FALSE(test, data->written[i]);
40062306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, data->vals[i], rval[i]);
40162306a36Sopenharmony_ci			break;
40262306a36Sopenharmony_ci		}
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	regmap_exit(map);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void stride(struct kunit *test)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
41162306a36Sopenharmony_ci	struct regmap *map;
41262306a36Sopenharmony_ci	struct regmap_config config;
41362306a36Sopenharmony_ci	struct regmap_ram_data *data;
41462306a36Sopenharmony_ci	unsigned int rval;
41562306a36Sopenharmony_ci	int i;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	config = test_regmap_config;
41862306a36Sopenharmony_ci	config.cache_type = t->type;
41962306a36Sopenharmony_ci	config.reg_stride = 2;
42062306a36Sopenharmony_ci	config.num_reg_defaults = BLOCK_TEST_SIZE / 2;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
42362306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
42462306a36Sopenharmony_ci	if (IS_ERR(map))
42562306a36Sopenharmony_ci		return;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* Only even registers can be accessed, try both read and write */
42862306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++) {
42962306a36Sopenharmony_ci		data->read[i] = false;
43062306a36Sopenharmony_ci		data->written[i] = false;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		if (i % 2) {
43362306a36Sopenharmony_ci			KUNIT_EXPECT_NE(test, 0, regmap_read(map, i, &rval));
43462306a36Sopenharmony_ci			KUNIT_EXPECT_NE(test, 0, regmap_write(map, i, rval));
43562306a36Sopenharmony_ci			KUNIT_EXPECT_FALSE(test, data->read[i]);
43662306a36Sopenharmony_ci			KUNIT_EXPECT_FALSE(test, data->written[i]);
43762306a36Sopenharmony_ci		} else {
43862306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &rval));
43962306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, data->vals[i], rval);
44062306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE,
44162306a36Sopenharmony_ci					data->read[i]);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, rval));
44462306a36Sopenharmony_ci			KUNIT_EXPECT_TRUE(test, data->written[i]);
44562306a36Sopenharmony_ci		}
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	regmap_exit(map);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic struct regmap_range_cfg test_range = {
45262306a36Sopenharmony_ci	.selector_reg = 1,
45362306a36Sopenharmony_ci	.selector_mask = 0xff,
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	.window_start = 4,
45662306a36Sopenharmony_ci	.window_len = 10,
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	.range_min = 20,
45962306a36Sopenharmony_ci	.range_max = 40,
46062306a36Sopenharmony_ci};
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic bool test_range_volatile(struct device *dev, unsigned int reg)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	if (reg >= test_range.window_start &&
46562306a36Sopenharmony_ci	    reg <= test_range.selector_reg + test_range.window_len)
46662306a36Sopenharmony_ci		return true;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (reg >= test_range.range_min && reg <= test_range.range_max)
46962306a36Sopenharmony_ci		return true;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	return false;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic void basic_ranges(struct kunit *test)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
47762306a36Sopenharmony_ci	struct regmap *map;
47862306a36Sopenharmony_ci	struct regmap_config config;
47962306a36Sopenharmony_ci	struct regmap_ram_data *data;
48062306a36Sopenharmony_ci	unsigned int val;
48162306a36Sopenharmony_ci	int i;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	config = test_regmap_config;
48462306a36Sopenharmony_ci	config.cache_type = t->type;
48562306a36Sopenharmony_ci	config.volatile_reg = test_range_volatile;
48662306a36Sopenharmony_ci	config.ranges = &test_range;
48762306a36Sopenharmony_ci	config.num_ranges = 1;
48862306a36Sopenharmony_ci	config.max_register = test_range.range_max;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
49162306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
49262306a36Sopenharmony_ci	if (IS_ERR(map))
49362306a36Sopenharmony_ci		return;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	for (i = test_range.range_min; i < test_range.range_max; i++) {
49662306a36Sopenharmony_ci		data->read[i] = false;
49762306a36Sopenharmony_ci		data->written[i] = false;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/* Reset the page to a non-zero value to trigger a change */
50162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_write(map, test_range.selector_reg,
50262306a36Sopenharmony_ci					      test_range.range_max));
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/* Check we set the page and use the window for writes */
50562306a36Sopenharmony_ci	data->written[test_range.selector_reg] = false;
50662306a36Sopenharmony_ci	data->written[test_range.window_start] = false;
50762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_write(map, test_range.range_min, 0));
50862306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, data->written[test_range.selector_reg]);
50962306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, data->written[test_range.window_start]);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	data->written[test_range.selector_reg] = false;
51262306a36Sopenharmony_ci	data->written[test_range.window_start] = false;
51362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_write(map,
51462306a36Sopenharmony_ci					      test_range.range_min +
51562306a36Sopenharmony_ci					      test_range.window_len,
51662306a36Sopenharmony_ci					      0));
51762306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, data->written[test_range.selector_reg]);
51862306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, data->written[test_range.window_start]);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/* Same for reads */
52162306a36Sopenharmony_ci	data->written[test_range.selector_reg] = false;
52262306a36Sopenharmony_ci	data->read[test_range.window_start] = false;
52362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_read(map, test_range.range_min, &val));
52462306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, data->written[test_range.selector_reg]);
52562306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, data->read[test_range.window_start]);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	data->written[test_range.selector_reg] = false;
52862306a36Sopenharmony_ci	data->read[test_range.window_start] = false;
52962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_read(map,
53062306a36Sopenharmony_ci					     test_range.range_min +
53162306a36Sopenharmony_ci					     test_range.window_len,
53262306a36Sopenharmony_ci					     &val));
53362306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, data->written[test_range.selector_reg]);
53462306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, data->read[test_range.window_start]);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* No physical access triggered in the virtual range */
53762306a36Sopenharmony_ci	for (i = test_range.range_min; i < test_range.range_max; i++) {
53862306a36Sopenharmony_ci		KUNIT_EXPECT_FALSE(test, data->read[i]);
53962306a36Sopenharmony_ci		KUNIT_EXPECT_FALSE(test, data->written[i]);
54062306a36Sopenharmony_ci	}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	regmap_exit(map);
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci/* Try to stress dynamic creation of cache data structures */
54662306a36Sopenharmony_cistatic void stress_insert(struct kunit *test)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
54962306a36Sopenharmony_ci	struct regmap *map;
55062306a36Sopenharmony_ci	struct regmap_config config;
55162306a36Sopenharmony_ci	struct regmap_ram_data *data;
55262306a36Sopenharmony_ci	unsigned int rval, *vals;
55362306a36Sopenharmony_ci	size_t buf_sz;
55462306a36Sopenharmony_ci	int i;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	config = test_regmap_config;
55762306a36Sopenharmony_ci	config.cache_type = t->type;
55862306a36Sopenharmony_ci	config.max_register = 300;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
56162306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
56262306a36Sopenharmony_ci	if (IS_ERR(map))
56362306a36Sopenharmony_ci		return;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	vals = kunit_kcalloc(test, sizeof(unsigned long), config.max_register,
56662306a36Sopenharmony_ci			     GFP_KERNEL);
56762306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, vals == NULL);
56862306a36Sopenharmony_ci	buf_sz = sizeof(unsigned long) * config.max_register;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	get_random_bytes(vals, buf_sz);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/* Write data into the map/cache in ever decreasing strides */
57362306a36Sopenharmony_ci	for (i = 0; i < config.max_register; i += 100)
57462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, vals[i]));
57562306a36Sopenharmony_ci	for (i = 0; i < config.max_register; i += 50)
57662306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, vals[i]));
57762306a36Sopenharmony_ci	for (i = 0; i < config.max_register; i += 25)
57862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, vals[i]));
57962306a36Sopenharmony_ci	for (i = 0; i < config.max_register; i += 10)
58062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, vals[i]));
58162306a36Sopenharmony_ci	for (i = 0; i < config.max_register; i += 5)
58262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, vals[i]));
58362306a36Sopenharmony_ci	for (i = 0; i < config.max_register; i += 3)
58462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, vals[i]));
58562306a36Sopenharmony_ci	for (i = 0; i < config.max_register; i += 2)
58662306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, vals[i]));
58762306a36Sopenharmony_ci	for (i = 0; i < config.max_register; i++)
58862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_write(map, i, vals[i]));
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	/* Do reads from the cache (if there is one) match? */
59162306a36Sopenharmony_ci	for (i = 0; i < config.max_register; i ++) {
59262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &rval));
59362306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, rval, vals[i]);
59462306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, t->type == REGCACHE_NONE, data->read[i]);
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	regmap_exit(map);
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic void cache_bypass(struct kunit *test)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
60362306a36Sopenharmony_ci	struct regmap *map;
60462306a36Sopenharmony_ci	struct regmap_config config;
60562306a36Sopenharmony_ci	struct regmap_ram_data *data;
60662306a36Sopenharmony_ci	unsigned int val, rval;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	config = test_regmap_config;
60962306a36Sopenharmony_ci	config.cache_type = t->type;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
61262306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
61362306a36Sopenharmony_ci	if (IS_ERR(map))
61462306a36Sopenharmony_ci		return;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* Ensure the cache has a value in it */
61962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 0, val));
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	/* Bypass then write a different value */
62262306a36Sopenharmony_ci	regcache_cache_bypass(map, true);
62362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 0, val + 1));
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	/* Read the bypassed value */
62662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 0, &rval));
62762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, val + 1, rval);
62862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, data->vals[0], rval);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* Disable bypass, the cache should still return the original value */
63162306a36Sopenharmony_ci	regcache_cache_bypass(map, false);
63262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 0, &rval));
63362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, val, rval);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	regmap_exit(map);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic void cache_sync(struct kunit *test)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
64162306a36Sopenharmony_ci	struct regmap *map;
64262306a36Sopenharmony_ci	struct regmap_config config;
64362306a36Sopenharmony_ci	struct regmap_ram_data *data;
64462306a36Sopenharmony_ci	unsigned int val[BLOCK_TEST_SIZE];
64562306a36Sopenharmony_ci	int i;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	config = test_regmap_config;
64862306a36Sopenharmony_ci	config.cache_type = t->type;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
65162306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
65262306a36Sopenharmony_ci	if (IS_ERR(map))
65362306a36Sopenharmony_ci		return;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* Put some data into the cache */
65862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_bulk_write(map, 0, val,
65962306a36Sopenharmony_ci						   BLOCK_TEST_SIZE));
66062306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
66162306a36Sopenharmony_ci		data->written[i] = false;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	/* Trash the data on the device itself then resync */
66462306a36Sopenharmony_ci	regcache_mark_dirty(map);
66562306a36Sopenharmony_ci	memset(data->vals, 0, sizeof(val));
66662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regcache_sync(map));
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	/* Did we just write the correct data out? */
66962306a36Sopenharmony_ci	KUNIT_EXPECT_MEMEQ(test, data->vals, val, sizeof(val));
67062306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
67162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, true, data->written[i]);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	regmap_exit(map);
67462306a36Sopenharmony_ci}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cistatic void cache_sync_defaults(struct kunit *test)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
67962306a36Sopenharmony_ci	struct regmap *map;
68062306a36Sopenharmony_ci	struct regmap_config config;
68162306a36Sopenharmony_ci	struct regmap_ram_data *data;
68262306a36Sopenharmony_ci	unsigned int val;
68362306a36Sopenharmony_ci	int i;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	config = test_regmap_config;
68662306a36Sopenharmony_ci	config.cache_type = t->type;
68762306a36Sopenharmony_ci	config.num_reg_defaults = BLOCK_TEST_SIZE;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
69062306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
69162306a36Sopenharmony_ci	if (IS_ERR(map))
69262306a36Sopenharmony_ci		return;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/* Change the value of one register */
69762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 2, val));
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/* Resync */
70062306a36Sopenharmony_ci	regcache_mark_dirty(map);
70162306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
70262306a36Sopenharmony_ci		data->written[i] = false;
70362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regcache_sync(map));
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* Did we just sync the one register we touched? */
70662306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
70762306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, i == 2, data->written[i]);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	regmap_exit(map);
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic void cache_sync_readonly(struct kunit *test)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
71562306a36Sopenharmony_ci	struct regmap *map;
71662306a36Sopenharmony_ci	struct regmap_config config;
71762306a36Sopenharmony_ci	struct regmap_ram_data *data;
71862306a36Sopenharmony_ci	unsigned int val;
71962306a36Sopenharmony_ci	int i;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	config = test_regmap_config;
72262306a36Sopenharmony_ci	config.cache_type = t->type;
72362306a36Sopenharmony_ci	config.writeable_reg = reg_5_false;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
72662306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
72762306a36Sopenharmony_ci	if (IS_ERR(map))
72862306a36Sopenharmony_ci		return;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	/* Read all registers to fill the cache */
73162306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
73262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &val));
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	/* Change the value of all registers, readonly should fail */
73562306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
73662306a36Sopenharmony_ci	regcache_cache_only(map, true);
73762306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
73862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, i != 5, regmap_write(map, i, val) == 0);
73962306a36Sopenharmony_ci	regcache_cache_only(map, false);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	/* Resync */
74262306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
74362306a36Sopenharmony_ci		data->written[i] = false;
74462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regcache_sync(map));
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/* Did that match what we see on the device? */
74762306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
74862306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, i != 5, data->written[i]);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	regmap_exit(map);
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic void cache_sync_patch(struct kunit *test)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
75662306a36Sopenharmony_ci	struct regmap *map;
75762306a36Sopenharmony_ci	struct regmap_config config;
75862306a36Sopenharmony_ci	struct regmap_ram_data *data;
75962306a36Sopenharmony_ci	struct reg_sequence patch[2];
76062306a36Sopenharmony_ci	unsigned int rval[BLOCK_TEST_SIZE], val;
76162306a36Sopenharmony_ci	int i;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	/* We need defaults so readback works */
76462306a36Sopenharmony_ci	config = test_regmap_config;
76562306a36Sopenharmony_ci	config.cache_type = t->type;
76662306a36Sopenharmony_ci	config.num_reg_defaults = BLOCK_TEST_SIZE;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
76962306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
77062306a36Sopenharmony_ci	if (IS_ERR(map))
77162306a36Sopenharmony_ci		return;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	/* Stash the original values */
77462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval,
77562306a36Sopenharmony_ci						  BLOCK_TEST_SIZE));
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	/* Patch a couple of values */
77862306a36Sopenharmony_ci	patch[0].reg = 2;
77962306a36Sopenharmony_ci	patch[0].def = rval[2] + 1;
78062306a36Sopenharmony_ci	patch[0].delay_us = 0;
78162306a36Sopenharmony_ci	patch[1].reg = 5;
78262306a36Sopenharmony_ci	patch[1].def = rval[5] + 1;
78362306a36Sopenharmony_ci	patch[1].delay_us = 0;
78462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_register_patch(map, patch,
78562306a36Sopenharmony_ci						       ARRAY_SIZE(patch)));
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci	/* Sync the cache */
78862306a36Sopenharmony_ci	regcache_mark_dirty(map);
78962306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
79062306a36Sopenharmony_ci		data->written[i] = false;
79162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regcache_sync(map));
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	/* The patch should be on the device but not in the cache */
79462306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++) {
79562306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &val));
79662306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, val, rval[i]);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci		switch (i) {
79962306a36Sopenharmony_ci		case 2:
80062306a36Sopenharmony_ci		case 5:
80162306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, true, data->written[i]);
80262306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, data->vals[i], rval[i] + 1);
80362306a36Sopenharmony_ci			break;
80462306a36Sopenharmony_ci		default:
80562306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, false, data->written[i]);
80662306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, data->vals[i], rval[i]);
80762306a36Sopenharmony_ci			break;
80862306a36Sopenharmony_ci		}
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	regmap_exit(map);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic void cache_drop(struct kunit *test)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
81762306a36Sopenharmony_ci	struct regmap *map;
81862306a36Sopenharmony_ci	struct regmap_config config;
81962306a36Sopenharmony_ci	struct regmap_ram_data *data;
82062306a36Sopenharmony_ci	unsigned int rval[BLOCK_TEST_SIZE];
82162306a36Sopenharmony_ci	int i;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	config = test_regmap_config;
82462306a36Sopenharmony_ci	config.cache_type = t->type;
82562306a36Sopenharmony_ci	config.num_reg_defaults = BLOCK_TEST_SIZE;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
82862306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
82962306a36Sopenharmony_ci	if (IS_ERR(map))
83062306a36Sopenharmony_ci		return;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	/* Ensure the data is read from the cache */
83362306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
83462306a36Sopenharmony_ci		data->read[i] = false;
83562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval,
83662306a36Sopenharmony_ci						  BLOCK_TEST_SIZE));
83762306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++) {
83862306a36Sopenharmony_ci		KUNIT_EXPECT_FALSE(test, data->read[i]);
83962306a36Sopenharmony_ci		data->read[i] = false;
84062306a36Sopenharmony_ci	}
84162306a36Sopenharmony_ci	KUNIT_EXPECT_MEMEQ(test, data->vals, rval, sizeof(rval));
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	/* Drop some registers */
84462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regcache_drop_region(map, 3, 5));
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	/* Reread and check only the dropped registers hit the device. */
84762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_bulk_read(map, 0, rval,
84862306a36Sopenharmony_ci						  BLOCK_TEST_SIZE));
84962306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
85062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, data->read[i], i >= 3 && i <= 5);
85162306a36Sopenharmony_ci	KUNIT_EXPECT_MEMEQ(test, data->vals, rval, sizeof(rval));
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	regmap_exit(map);
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic void cache_present(struct kunit *test)
85762306a36Sopenharmony_ci{
85862306a36Sopenharmony_ci	struct regcache_types *t = (struct regcache_types *)test->param_value;
85962306a36Sopenharmony_ci	struct regmap *map;
86062306a36Sopenharmony_ci	struct regmap_config config;
86162306a36Sopenharmony_ci	struct regmap_ram_data *data;
86262306a36Sopenharmony_ci	unsigned int val;
86362306a36Sopenharmony_ci	int i;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	config = test_regmap_config;
86662306a36Sopenharmony_ci	config.cache_type = t->type;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	map = gen_regmap(&config, &data);
86962306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
87062306a36Sopenharmony_ci	if (IS_ERR(map))
87162306a36Sopenharmony_ci		return;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
87462306a36Sopenharmony_ci		data->read[i] = false;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/* No defaults so no registers cached. */
87762306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
87862306a36Sopenharmony_ci		KUNIT_ASSERT_FALSE(test, regcache_reg_cached(map, i));
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* We didn't trigger any reads */
88162306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
88262306a36Sopenharmony_ci		KUNIT_ASSERT_FALSE(test, data->read[i]);
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	/* Fill the cache */
88562306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
88662306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &val));
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	/* Now everything should be cached */
88962306a36Sopenharmony_ci	for (i = 0; i < BLOCK_TEST_SIZE; i++)
89062306a36Sopenharmony_ci		KUNIT_ASSERT_TRUE(test, regcache_reg_cached(map, i));
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	regmap_exit(map);
89362306a36Sopenharmony_ci}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistruct raw_test_types {
89662306a36Sopenharmony_ci	const char *name;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	enum regcache_type cache_type;
89962306a36Sopenharmony_ci	enum regmap_endian val_endian;
90062306a36Sopenharmony_ci};
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_cistatic void raw_to_desc(const struct raw_test_types *t, char *desc)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	strcpy(desc, t->name);
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic const struct raw_test_types raw_types_list[] = {
90862306a36Sopenharmony_ci	{ "none-little",   REGCACHE_NONE,   REGMAP_ENDIAN_LITTLE },
90962306a36Sopenharmony_ci	{ "none-big",      REGCACHE_NONE,   REGMAP_ENDIAN_BIG },
91062306a36Sopenharmony_ci	{ "flat-little",   REGCACHE_FLAT,   REGMAP_ENDIAN_LITTLE },
91162306a36Sopenharmony_ci	{ "flat-big",      REGCACHE_FLAT,   REGMAP_ENDIAN_BIG },
91262306a36Sopenharmony_ci	{ "rbtree-little", REGCACHE_RBTREE, REGMAP_ENDIAN_LITTLE },
91362306a36Sopenharmony_ci	{ "rbtree-big",    REGCACHE_RBTREE, REGMAP_ENDIAN_BIG },
91462306a36Sopenharmony_ci	{ "maple-little",  REGCACHE_MAPLE,  REGMAP_ENDIAN_LITTLE },
91562306a36Sopenharmony_ci	{ "maple-big",     REGCACHE_MAPLE,  REGMAP_ENDIAN_BIG },
91662306a36Sopenharmony_ci};
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(raw_test_types, raw_types_list, raw_to_desc);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_cistatic const struct raw_test_types raw_cache_types_list[] = {
92162306a36Sopenharmony_ci	{ "flat-little",   REGCACHE_FLAT,   REGMAP_ENDIAN_LITTLE },
92262306a36Sopenharmony_ci	{ "flat-big",      REGCACHE_FLAT,   REGMAP_ENDIAN_BIG },
92362306a36Sopenharmony_ci	{ "rbtree-little", REGCACHE_RBTREE, REGMAP_ENDIAN_LITTLE },
92462306a36Sopenharmony_ci	{ "rbtree-big",    REGCACHE_RBTREE, REGMAP_ENDIAN_BIG },
92562306a36Sopenharmony_ci	{ "maple-little",  REGCACHE_MAPLE,  REGMAP_ENDIAN_LITTLE },
92662306a36Sopenharmony_ci	{ "maple-big",     REGCACHE_MAPLE,  REGMAP_ENDIAN_BIG },
92762306a36Sopenharmony_ci};
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(raw_test_cache_types, raw_cache_types_list, raw_to_desc);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_cistatic const struct regmap_config raw_regmap_config = {
93262306a36Sopenharmony_ci	.max_register = BLOCK_TEST_SIZE,
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	.reg_format_endian = REGMAP_ENDIAN_LITTLE,
93562306a36Sopenharmony_ci	.reg_bits = 16,
93662306a36Sopenharmony_ci	.val_bits = 16,
93762306a36Sopenharmony_ci};
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic struct regmap *gen_raw_regmap(struct regmap_config *config,
94062306a36Sopenharmony_ci				     struct raw_test_types *test_type,
94162306a36Sopenharmony_ci				     struct regmap_ram_data **data)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	u16 *buf;
94462306a36Sopenharmony_ci	struct regmap *ret;
94562306a36Sopenharmony_ci	size_t size = (config->max_register + 1) * config->reg_bits / 8;
94662306a36Sopenharmony_ci	int i;
94762306a36Sopenharmony_ci	struct reg_default *defaults;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	config->cache_type = test_type->cache_type;
95062306a36Sopenharmony_ci	config->val_format_endian = test_type->val_endian;
95162306a36Sopenharmony_ci	config->disable_locking = config->cache_type == REGCACHE_RBTREE ||
95262306a36Sopenharmony_ci					config->cache_type == REGCACHE_MAPLE;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	buf = kmalloc(size, GFP_KERNEL);
95562306a36Sopenharmony_ci	if (!buf)
95662306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	get_random_bytes(buf, size);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	*data = kzalloc(sizeof(**data), GFP_KERNEL);
96162306a36Sopenharmony_ci	if (!(*data))
96262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
96362306a36Sopenharmony_ci	(*data)->vals = (void *)buf;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	config->num_reg_defaults = config->max_register + 1;
96662306a36Sopenharmony_ci	defaults = kcalloc(config->num_reg_defaults,
96762306a36Sopenharmony_ci			   sizeof(struct reg_default),
96862306a36Sopenharmony_ci			   GFP_KERNEL);
96962306a36Sopenharmony_ci	if (!defaults)
97062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
97162306a36Sopenharmony_ci	config->reg_defaults = defaults;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	for (i = 0; i < config->num_reg_defaults; i++) {
97462306a36Sopenharmony_ci		defaults[i].reg = i;
97562306a36Sopenharmony_ci		switch (test_type->val_endian) {
97662306a36Sopenharmony_ci		case REGMAP_ENDIAN_LITTLE:
97762306a36Sopenharmony_ci			defaults[i].def = le16_to_cpu(buf[i]);
97862306a36Sopenharmony_ci			break;
97962306a36Sopenharmony_ci		case REGMAP_ENDIAN_BIG:
98062306a36Sopenharmony_ci			defaults[i].def = be16_to_cpu(buf[i]);
98162306a36Sopenharmony_ci			break;
98262306a36Sopenharmony_ci		default:
98362306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
98462306a36Sopenharmony_ci		}
98562306a36Sopenharmony_ci	}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	/*
98862306a36Sopenharmony_ci	 * We use the defaults in the tests but they don't make sense
98962306a36Sopenharmony_ci	 * to the core if there's no cache.
99062306a36Sopenharmony_ci	 */
99162306a36Sopenharmony_ci	if (config->cache_type == REGCACHE_NONE)
99262306a36Sopenharmony_ci		config->num_reg_defaults = 0;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	ret = regmap_init_raw_ram(config, *data);
99562306a36Sopenharmony_ci	if (IS_ERR(ret)) {
99662306a36Sopenharmony_ci		kfree(buf);
99762306a36Sopenharmony_ci		kfree(*data);
99862306a36Sopenharmony_ci	}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	return ret;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic void raw_read_defaults_single(struct kunit *test)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	struct raw_test_types *t = (struct raw_test_types *)test->param_value;
100662306a36Sopenharmony_ci	struct regmap *map;
100762306a36Sopenharmony_ci	struct regmap_config config;
100862306a36Sopenharmony_ci	struct regmap_ram_data *data;
100962306a36Sopenharmony_ci	unsigned int rval;
101062306a36Sopenharmony_ci	int i;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	config = raw_regmap_config;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	map = gen_raw_regmap(&config, t, &data);
101562306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
101662306a36Sopenharmony_ci	if (IS_ERR(map))
101762306a36Sopenharmony_ci		return;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	/* Check that we can read the defaults via the API */
102062306a36Sopenharmony_ci	for (i = 0; i < config.max_register + 1; i++) {
102162306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &rval));
102262306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, config.reg_defaults[i].def, rval);
102362306a36Sopenharmony_ci	}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	regmap_exit(map);
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_cistatic void raw_read_defaults(struct kunit *test)
102962306a36Sopenharmony_ci{
103062306a36Sopenharmony_ci	struct raw_test_types *t = (struct raw_test_types *)test->param_value;
103162306a36Sopenharmony_ci	struct regmap *map;
103262306a36Sopenharmony_ci	struct regmap_config config;
103362306a36Sopenharmony_ci	struct regmap_ram_data *data;
103462306a36Sopenharmony_ci	u16 *rval;
103562306a36Sopenharmony_ci	u16 def;
103662306a36Sopenharmony_ci	size_t val_len;
103762306a36Sopenharmony_ci	int i;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	config = raw_regmap_config;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	map = gen_raw_regmap(&config, t, &data);
104262306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
104362306a36Sopenharmony_ci	if (IS_ERR(map))
104462306a36Sopenharmony_ci		return;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	val_len = sizeof(*rval) * (config.max_register + 1);
104762306a36Sopenharmony_ci	rval = kmalloc(val_len, GFP_KERNEL);
104862306a36Sopenharmony_ci	KUNIT_ASSERT_TRUE(test, rval != NULL);
104962306a36Sopenharmony_ci	if (!rval)
105062306a36Sopenharmony_ci		return;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	/* Check that we can read the defaults via the API */
105362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_raw_read(map, 0, rval, val_len));
105462306a36Sopenharmony_ci	for (i = 0; i < config.max_register + 1; i++) {
105562306a36Sopenharmony_ci		def = config.reg_defaults[i].def;
105662306a36Sopenharmony_ci		if (config.val_format_endian == REGMAP_ENDIAN_BIG) {
105762306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, def, be16_to_cpu(rval[i]));
105862306a36Sopenharmony_ci		} else {
105962306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, def, le16_to_cpu(rval[i]));
106062306a36Sopenharmony_ci		}
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	kfree(rval);
106462306a36Sopenharmony_ci	regmap_exit(map);
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_cistatic void raw_write_read_single(struct kunit *test)
106862306a36Sopenharmony_ci{
106962306a36Sopenharmony_ci	struct raw_test_types *t = (struct raw_test_types *)test->param_value;
107062306a36Sopenharmony_ci	struct regmap *map;
107162306a36Sopenharmony_ci	struct regmap_config config;
107262306a36Sopenharmony_ci	struct regmap_ram_data *data;
107362306a36Sopenharmony_ci	u16 val;
107462306a36Sopenharmony_ci	unsigned int rval;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	config = raw_regmap_config;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	map = gen_raw_regmap(&config, t, &data);
107962306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
108062306a36Sopenharmony_ci	if (IS_ERR(map))
108162306a36Sopenharmony_ci		return;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	/* If we write a value to a register we can read it back */
108662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 0, val));
108762306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 0, &rval));
108862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, val, rval);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	regmap_exit(map);
109162306a36Sopenharmony_ci}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_cistatic void raw_write(struct kunit *test)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	struct raw_test_types *t = (struct raw_test_types *)test->param_value;
109662306a36Sopenharmony_ci	struct regmap *map;
109762306a36Sopenharmony_ci	struct regmap_config config;
109862306a36Sopenharmony_ci	struct regmap_ram_data *data;
109962306a36Sopenharmony_ci	u16 *hw_buf;
110062306a36Sopenharmony_ci	u16 val[2];
110162306a36Sopenharmony_ci	unsigned int rval;
110262306a36Sopenharmony_ci	int i;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	config = raw_regmap_config;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	map = gen_raw_regmap(&config, t, &data);
110762306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
110862306a36Sopenharmony_ci	if (IS_ERR(map))
110962306a36Sopenharmony_ci		return;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	hw_buf = (u16 *)data->vals;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	get_random_bytes(&val, sizeof(val));
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	/* Do a raw write */
111662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_raw_write(map, 2, val, sizeof(val)));
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	/* We should read back the new values, and defaults for the rest */
111962306a36Sopenharmony_ci	for (i = 0; i < config.max_register + 1; i++) {
112062306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &rval));
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		switch (i) {
112362306a36Sopenharmony_ci		case 2:
112462306a36Sopenharmony_ci		case 3:
112562306a36Sopenharmony_ci			if (config.val_format_endian == REGMAP_ENDIAN_BIG) {
112662306a36Sopenharmony_ci				KUNIT_EXPECT_EQ(test, rval,
112762306a36Sopenharmony_ci						be16_to_cpu(val[i % 2]));
112862306a36Sopenharmony_ci			} else {
112962306a36Sopenharmony_ci				KUNIT_EXPECT_EQ(test, rval,
113062306a36Sopenharmony_ci						le16_to_cpu(val[i % 2]));
113162306a36Sopenharmony_ci			}
113262306a36Sopenharmony_ci			break;
113362306a36Sopenharmony_ci		default:
113462306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, config.reg_defaults[i].def, rval);
113562306a36Sopenharmony_ci			break;
113662306a36Sopenharmony_ci		}
113762306a36Sopenharmony_ci	}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	/* The values should appear in the "hardware" */
114062306a36Sopenharmony_ci	KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], val, sizeof(val));
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	regmap_exit(map);
114362306a36Sopenharmony_ci}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_cistatic void raw_sync(struct kunit *test)
114662306a36Sopenharmony_ci{
114762306a36Sopenharmony_ci	struct raw_test_types *t = (struct raw_test_types *)test->param_value;
114862306a36Sopenharmony_ci	struct regmap *map;
114962306a36Sopenharmony_ci	struct regmap_config config;
115062306a36Sopenharmony_ci	struct regmap_ram_data *data;
115162306a36Sopenharmony_ci	u16 val[3];
115262306a36Sopenharmony_ci	u16 *hw_buf;
115362306a36Sopenharmony_ci	unsigned int rval;
115462306a36Sopenharmony_ci	int i;
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	config = raw_regmap_config;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	map = gen_raw_regmap(&config, t, &data);
115962306a36Sopenharmony_ci	KUNIT_ASSERT_FALSE(test, IS_ERR(map));
116062306a36Sopenharmony_ci	if (IS_ERR(map))
116162306a36Sopenharmony_ci		return;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	hw_buf = (u16 *)data->vals;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	get_changed_bytes(&hw_buf[2], &val[0], sizeof(val));
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	/* Do a regular write and a raw write in cache only mode */
116862306a36Sopenharmony_ci	regcache_cache_only(map, true);
116962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_raw_write(map, 2, val,
117062306a36Sopenharmony_ci						  sizeof(u16) * 2));
117162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 4, val[2]));
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	/* We should read back the new values, and defaults for the rest */
117462306a36Sopenharmony_ci	for (i = 0; i < config.max_register + 1; i++) {
117562306a36Sopenharmony_ci		KUNIT_EXPECT_EQ(test, 0, regmap_read(map, i, &rval));
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci		switch (i) {
117862306a36Sopenharmony_ci		case 2:
117962306a36Sopenharmony_ci		case 3:
118062306a36Sopenharmony_ci			if (config.val_format_endian == REGMAP_ENDIAN_BIG) {
118162306a36Sopenharmony_ci				KUNIT_EXPECT_EQ(test, rval,
118262306a36Sopenharmony_ci						be16_to_cpu(val[i - 2]));
118362306a36Sopenharmony_ci			} else {
118462306a36Sopenharmony_ci				KUNIT_EXPECT_EQ(test, rval,
118562306a36Sopenharmony_ci						le16_to_cpu(val[i - 2]));
118662306a36Sopenharmony_ci			}
118762306a36Sopenharmony_ci			break;
118862306a36Sopenharmony_ci		case 4:
118962306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, rval, val[i - 2]);
119062306a36Sopenharmony_ci			break;
119162306a36Sopenharmony_ci		default:
119262306a36Sopenharmony_ci			KUNIT_EXPECT_EQ(test, config.reg_defaults[i].def, rval);
119362306a36Sopenharmony_ci			break;
119462306a36Sopenharmony_ci		}
119562306a36Sopenharmony_ci	}
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/*
119862306a36Sopenharmony_ci	 * The value written via _write() was translated by the core,
119962306a36Sopenharmony_ci	 * translate the original copy for comparison purposes.
120062306a36Sopenharmony_ci	 */
120162306a36Sopenharmony_ci	if (config.val_format_endian == REGMAP_ENDIAN_BIG)
120262306a36Sopenharmony_ci		val[2] = cpu_to_be16(val[2]);
120362306a36Sopenharmony_ci	else
120462306a36Sopenharmony_ci		val[2] = cpu_to_le16(val[2]);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	/* The values should not appear in the "hardware" */
120762306a36Sopenharmony_ci	KUNIT_EXPECT_MEMNEQ(test, &hw_buf[2], &val[0], sizeof(val));
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	for (i = 0; i < config.max_register + 1; i++)
121062306a36Sopenharmony_ci		data->written[i] = false;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	/* Do the sync */
121362306a36Sopenharmony_ci	regcache_cache_only(map, false);
121462306a36Sopenharmony_ci	regcache_mark_dirty(map);
121562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, 0, regcache_sync(map));
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	/* The values should now appear in the "hardware" */
121862306a36Sopenharmony_ci	KUNIT_EXPECT_MEMEQ(test, &hw_buf[2], &val[0], sizeof(val));
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	regmap_exit(map);
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic struct kunit_case regmap_test_cases[] = {
122462306a36Sopenharmony_ci	KUNIT_CASE_PARAM(basic_read_write, regcache_types_gen_params),
122562306a36Sopenharmony_ci	KUNIT_CASE_PARAM(bulk_write, regcache_types_gen_params),
122662306a36Sopenharmony_ci	KUNIT_CASE_PARAM(bulk_read, regcache_types_gen_params),
122762306a36Sopenharmony_ci	KUNIT_CASE_PARAM(write_readonly, regcache_types_gen_params),
122862306a36Sopenharmony_ci	KUNIT_CASE_PARAM(read_writeonly, regcache_types_gen_params),
122962306a36Sopenharmony_ci	KUNIT_CASE_PARAM(reg_defaults, regcache_types_gen_params),
123062306a36Sopenharmony_ci	KUNIT_CASE_PARAM(reg_defaults_read_dev, regcache_types_gen_params),
123162306a36Sopenharmony_ci	KUNIT_CASE_PARAM(register_patch, regcache_types_gen_params),
123262306a36Sopenharmony_ci	KUNIT_CASE_PARAM(stride, regcache_types_gen_params),
123362306a36Sopenharmony_ci	KUNIT_CASE_PARAM(basic_ranges, regcache_types_gen_params),
123462306a36Sopenharmony_ci	KUNIT_CASE_PARAM(stress_insert, regcache_types_gen_params),
123562306a36Sopenharmony_ci	KUNIT_CASE_PARAM(cache_bypass, real_cache_types_gen_params),
123662306a36Sopenharmony_ci	KUNIT_CASE_PARAM(cache_sync, real_cache_types_gen_params),
123762306a36Sopenharmony_ci	KUNIT_CASE_PARAM(cache_sync_defaults, real_cache_types_gen_params),
123862306a36Sopenharmony_ci	KUNIT_CASE_PARAM(cache_sync_readonly, real_cache_types_gen_params),
123962306a36Sopenharmony_ci	KUNIT_CASE_PARAM(cache_sync_patch, real_cache_types_gen_params),
124062306a36Sopenharmony_ci	KUNIT_CASE_PARAM(cache_drop, sparse_cache_types_gen_params),
124162306a36Sopenharmony_ci	KUNIT_CASE_PARAM(cache_present, sparse_cache_types_gen_params),
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	KUNIT_CASE_PARAM(raw_read_defaults_single, raw_test_types_gen_params),
124462306a36Sopenharmony_ci	KUNIT_CASE_PARAM(raw_read_defaults, raw_test_types_gen_params),
124562306a36Sopenharmony_ci	KUNIT_CASE_PARAM(raw_write_read_single, raw_test_types_gen_params),
124662306a36Sopenharmony_ci	KUNIT_CASE_PARAM(raw_write, raw_test_types_gen_params),
124762306a36Sopenharmony_ci	KUNIT_CASE_PARAM(raw_sync, raw_test_cache_types_gen_params),
124862306a36Sopenharmony_ci	{}
124962306a36Sopenharmony_ci};
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic struct kunit_suite regmap_test_suite = {
125262306a36Sopenharmony_ci	.name = "regmap",
125362306a36Sopenharmony_ci	.test_cases = regmap_test_cases,
125462306a36Sopenharmony_ci};
125562306a36Sopenharmony_cikunit_test_suite(regmap_test_suite);
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1258