Skip to content

Commit 09e70e4

Browse files
andy-shevbroonie
authored andcommitted
regmap: Synchronize cache for the page selector
If the selector register is represented in each page, its value according to the debugfs is stale because it gets synchronized only after the real page switch happens. Hence the regmap cache initialisation from the HW inherits outdated data in the selector register. Synchronize cache for the page selector just in time. Before (offset followed by hexdump, the first byte is selector): // Real registers 18: 05 ff 00 00 ff 0f 00 00 f0 00 00 00 ... // Virtual (per port) 40: 05 ff 00 00 e0 e0 00 00 00 00 00 1f 50: 00 ff 00 00 e0 e0 00 00 00 00 00 1f 60: 01 ff 00 00 ff ff 00 00 00 00 00 00 70: 02 ff 00 00 cf f3 00 00 00 00 00 0c 80: 03 ff 00 00 00 00 00 00 00 00 00 ff 90: 04 ff 00 00 ff 0f 00 00 f0 00 00 00 After: // Real registers 18: 05 ff 00 00 ff 0f 00 00 f0 00 00 00 ... // Virtual (per port) 40: 00 ff 00 00 e0 e0 00 00 00 00 00 1f 50: 01 ff 00 00 e0 e0 00 00 00 00 00 1f 60: 02 ff 00 00 ff ff 00 00 00 00 00 00 70: 03 ff 00 00 cf f3 00 00 00 00 00 0c 80: 04 ff 00 00 00 00 00 00 00 00 00 ff 90: 05 ff 00 00 ff 0f 00 00 f0 00 00 00 Fixes: 6863ca6 ("regmap: Add support for register indirect addressing.") Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://patch.msgid.link/20260302184753.2693803-1-andriy.shevchenko@linux.intel.com Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent f338e77 commit 09e70e4

1 file changed

Lines changed: 26 additions & 4 deletions

File tree

drivers/base/regmap/regmap.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
15451545
unsigned int val_num)
15461546
{
15471547
void *orig_work_buf;
1548+
unsigned int selector_reg;
15481549
unsigned int win_offset;
15491550
unsigned int win_page;
15501551
bool page_chg;
@@ -1563,10 +1564,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
15631564
return -EINVAL;
15641565
}
15651566

1566-
/* It is possible to have selector register inside data window.
1567-
In that case, selector register is located on every page and
1568-
it needs no page switching, when accessed alone. */
1567+
/*
1568+
* Calculate the address of the selector register in the corresponding
1569+
* data window if it is located on every page.
1570+
*/
1571+
page_chg = in_range(range->selector_reg, range->window_start, range->window_len);
1572+
if (page_chg)
1573+
selector_reg = range->range_min + win_page * range->window_len +
1574+
range->selector_reg - range->window_start;
1575+
1576+
/*
1577+
* It is possible to have selector register inside data window.
1578+
* In that case, selector register is located on every page and it
1579+
* needs no page switching, when accessed alone.
1580+
*
1581+
* Nevertheless we should synchronize the cache values for it.
1582+
* This can't be properly achieved if the selector register is
1583+
* the first and the only one to be read inside the data window.
1584+
* That's why we update it in that case as well.
1585+
*
1586+
* However, we specifically avoid updating it for the default page,
1587+
* when it's overlapped with the real data window, to prevent from
1588+
* infinite looping.
1589+
*/
15691590
if (val_num > 1 ||
1591+
(page_chg && selector_reg != range->selector_reg) ||
15701592
range->window_start + win_offset != range->selector_reg) {
15711593
/* Use separate work_buf during page switching */
15721594
orig_work_buf = map->work_buf;
@@ -1575,7 +1597,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
15751597
ret = _regmap_update_bits(map, range->selector_reg,
15761598
range->selector_mask,
15771599
win_page << range->selector_shift,
1578-
&page_chg, false);
1600+
NULL, false);
15791601

15801602
map->work_buf = orig_work_buf;
15811603

0 commit comments

Comments
 (0)