blob: 1198baabd7f19d20779497984ff1e7ec514c1ecf [file]
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 Silicon Laboratories Inc.
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/drivers/cache.h>
#include <zephyr/sys/barrier.h>
#include "rsi_pll.h"
/*
* The SiWx91x has an external AHB instruction cache for the QSPI flash. It
* has no data cache. The cache clock is controlled via the M4CLK set/clear
* register pair. There is no dedicated invalidate command: toggling the clock
* gate implicitly clears all cached lines.
*/
static bool icache_is_enabled(void)
{
return !!(M4CLK->CLK_ENABLE_SET_REG3 & ICACHE_ENABLE);
}
/* Instruction cache */
void cache_instr_enable(void)
{
M4CLK->CLK_ENABLE_SET_REG3 = ICACHE_ENABLE;
}
void cache_instr_disable(void)
{
M4CLK->CLK_ENABLE_CLEAR_REG3 = ICACHE_ENABLE;
barrier_isync_fence_full();
}
int cache_instr_flush_all(void)
{
/* Instruction cache is read-only: no dirty lines to write back */
return -ENOTSUP;
}
int cache_instr_invd_all(void)
{
if (!icache_is_enabled()) {
return -EAGAIN;
}
/*
* Toggle the clock gate to clear all cached lines. The cache restarts
* empty after re-enabling. Follow with an ISB to flush the Cortex-M4
* instruction pipeline.
*/
M4CLK->CLK_ENABLE_CLEAR_REG3 = ICACHE_ENABLE;
M4CLK->CLK_ENABLE_SET_REG3 = ICACHE_ENABLE;
barrier_isync_fence_full();
return 0;
}
int cache_instr_flush_and_invd_all(void)
{
/* Instruction cache is read-only, so flush is a no-op before invalidate */
return cache_instr_invd_all();
}
int cache_instr_flush_range(void *addr, size_t size)
{
return -ENOTSUP;
}
int cache_instr_invd_range(void *addr, size_t size)
{
/* No per-line control available: fall back to full invalidation */
return cache_instr_invd_all();
}
int cache_instr_flush_and_invd_range(void *addr, size_t size)
{
return cache_instr_invd_range(addr, size);
}