1/*
2 * Copyright (c) 2022 BayLibre, SAS
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#include <zephyr/toolchain.h>
8#include <zephyr/linker/sections.h>
9#include <zephyr/arch/cpu.h>
10#include "asm_macros.inc"
11
12#define CSR_PMPCFG_BASE  0x3a0
13#define CSR_PMPADDR_BASE 0x3b0
14
15/*
16 * Prototype:
17 *
18 * void z_riscv_write_pmp_entries(unsigned int start,		// a0
19 *                                unsigned int end,		// a1
20 *                                bool clear_trailing_entries,	// a2
21 *                                unsigned long *pmp_addr,		// a3
22 *                                unsigned long *pmp_cfg)		// a4
23 *
24 * Called from pmp.c to write a range of PMP entries.
25 *
26 * PMP registers are accessed with the csr instruction which only takes an
27 * immediate value as the actual register. In order to avoid traversing
28 * the whole register list, we use the start index to jump directly to the
29 * location corresponding to the start of the wanted range. For this to work
30 * we disallow compressed instructions so the update block sizes are easily
31 * known (luckily they're all power-of-2's simplifying the code further).
32 *
33 * start < end && end <= CONFIG_PMP_SLOTS must be true.
34 */
35
36GTEXT(z_riscv_write_pmp_entries)
37SECTION_FUNC(TEXT, z_riscv_write_pmp_entries)
38
39	la t0, pmpaddr_store
40	slli t1, a0, 4  /* 16-byte instruction blocks */
41	add t0, t0, t1
42	jr t0
43
44pmpaddr_store:
45
46	.option push
47	.option norvc
48	.set _index, 0
49	.rept CONFIG_PMP_SLOTS
50	lr t0, (RV_REGSIZE * _index)(a3)
51	li t1, _index + 1
52	csrw (CSR_PMPADDR_BASE + _index), t0
53	beq t1, a1, pmpaddr_done
54	.set _index, _index + 1
55	.endr
56	.option pop
57
58pmpaddr_done:
59
60	/*
61	 * Move to the pmpcfg space:
62	 * a0 = a0 / RV_REGSIZE
63	 * a1 = (a1 + RV_REGSIZE - 1) / RV_REGSIZE
64	 */
65	la t0, pmpcfg_store
66	srli a0, a0, RV_REGSHIFT
67	slli t1, a0, 4  /* 16-byte instruction blocks */
68	add t0, t0, t1
69	addi a1, a1, RV_REGSIZE - 1
70	srli a1, a1, RV_REGSHIFT
71	jr t0
72
73pmpcfg_store:
74
75	.option push
76	.option norvc
77	.set _index, 0
78	.rept (CONFIG_PMP_SLOTS / RV_REGSIZE)
79	lr t0, (RV_REGSIZE * _index)(a4)
80	addi a0, a0, 1
81	csrw (CSR_PMPCFG_BASE + RV_REGSIZE/4 * _index), t0
82	beq a0, a1, pmpcfg_done
83	.set _index, _index + 1
84	.endr
85	.option pop
86
87pmpcfg_done:
88
89	beqz a2, done
90
91	la t0, pmpcfg_zerotail
92	slli a0, a0, 2  /* 4-byte instruction blocks */
93	add t0, t0, a0
94	jr t0
95
96pmpcfg_zerotail:
97
98	.option push
99	.option norvc
100	.set _index, 0
101	.rept (CONFIG_PMP_SLOTS / RV_REGSIZE)
102	csrw (CSR_PMPCFG_BASE + RV_REGSIZE/4 * _index), zero
103	.set _index, _index + 1
104	.endr
105	.option pop
106
107done:	ret
108