* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <arch_helpers.h>
#include <debug.h>
#include <errno.h>
#include <mmio.h>
#include <platform.h>
#include <platform_def.h>
#include <sunxi_def.h>
+#include <sunxi_mmap.h>
#include <sunxi_private.h>
#include <xlat_tables_v2.h>
return 0;
}
+
+/* This lock synchronises access to the arisc management processor. */
+DEFINE_BAKERY_LOCK(arisc_lock);
+
+/*
+ * Tell the "arisc" SCP core (an OpenRISC core) to execute some code.
+ * We don't have any service running there, so we place some OpenRISC code
+ * in SRAM, put the address of that into the reset vector and release the
+ * arisc reset line. The SCP will execute that code and pull the line up again.
+ */
+void sunxi_execute_arisc_code(uint32_t *code, size_t size,
+ int patch_offset, uint16_t param)
+{
+ uintptr_t arisc_reset_vec = SUNXI_SRAM_A2_BASE - 0x4000 + 0x100;
+
+ do {
+ bakery_lock_get(&arisc_lock);
+ /* Wait until the arisc is in reset state. */
+ if (!(mmio_read_32(SUNXI_R_CPUCFG_BASE) & BIT(0)))
+ break;
+
+ bakery_lock_release(&arisc_lock);
+ } while (1);
+
+ /* Patch up the code to feed in an input parameter. */
+ if (patch_offset >= 0 && patch_offset <= (size - 4))
+ code[patch_offset] = (code[patch_offset] & ~0xffff) | param;
+ clean_dcache_range((uintptr_t)code, size);
+
+ /*
+ * The OpenRISC unconditional branch has opcode 0, the branch offset
+ * is in the lower 26 bits, containing the distance to the target,
+ * in instruction granularity (32 bits).
+ */
+ mmio_write_32(arisc_reset_vec, ((uintptr_t)code - arisc_reset_vec) / 4);
+ clean_dcache_range(arisc_reset_vec, 4);
+
+ /* De-assert the arisc reset line to let it run. */
+ mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
+
+ /*
+ * We release the lock here, although the arisc is still busy.
+ * But as long as it runs, the reset line is high, so other users
+ * won't leave the loop above.
+ * Once it has finished, the code is supposed to clear the reset line,
+ * to signal this to other users.
+ */
+ bakery_lock_release(&arisc_lock);
+}