Software APIs
rram_ctrl_testutils.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "sw/device/lib/testing/rram_ctrl_testutils.h"
6
7#include <assert.h>
8#include <stdbool.h>
9#include <stdint.h>
10
16#include "sw/device/lib/testing/test_framework/check.h"
17
18#include "hw/top/rram_ctrl_regs.h" // Generated
19
20#define MODULE_ID MAKE_MODULE_ID('r', 'c', 't')
21
22status_t rram_ctrl_testutils_wait_for_init(dif_rram_ctrl_state_t *rram_state) {
24 do {
25 TRY(dif_rram_ctrl_get_status(rram_state, &status));
26 } while (status.controller_init_done == 0);
27 return OK_STATUS();
28}
29
30status_t rram_ctrl_testutils_wait_transaction_end(
31 dif_rram_ctrl_state_t *rram_state) {
32 dif_rram_ctrl_output_t output;
34 do {
35 dif_result = dif_rram_ctrl_end(rram_state, &output);
36 TRY_CHECK(dif_result != kDifBadArg);
37 TRY_CHECK(dif_result != kDifError);
38 } while (dif_result != kDifOk);
39
40 if (output.operation_error) {
41 dif_rram_ctrl_error_codes_t codes = output.error_code.codes;
42 uint32_t error_reg = 0;
43 error_reg = bitfield_bit32_write(error_reg, RRAM_CTRL_ERR_CODE_OP_ERR_BIT,
44 codes.operation_error);
45 error_reg = bitfield_bit32_write(error_reg, RRAM_CTRL_ERR_CODE_MP_ERR_BIT,
47 error_reg = bitfield_bit32_write(error_reg, RRAM_CTRL_ERR_CODE_RD_ERR_BIT,
48 codes.read_error);
49 error_reg = bitfield_bit32_write(error_reg, RRAM_CTRL_ERR_CODE_WR_ERR_BIT,
50 codes.write_error);
51 }
52 TRY(dif_rram_ctrl_clear_error_codes(rram_state, output.error_code.codes));
53 return output.operation_error == 0 ? OK_STATUS() : INTERNAL();
54}
55
56status_t rram_ctrl_testutils_data_region_setup_properties(
57 dif_rram_ctrl_state_t *rram_state, uint32_t base_page_index,
58 uint32_t data_region, uint32_t region_size,
59 dif_rram_ctrl_region_properties_t region_properties, uint32_t *offset) {
60 dif_rram_ctrl_data_region_properties_t data_region_properties = {
61 .base = base_page_index,
62 .properties = region_properties,
63 .size = region_size};
64
65 TRY(dif_rram_ctrl_set_data_region_properties(rram_state, data_region,
66 data_region_properties));
67 TRY(dif_rram_ctrl_set_data_region_enablement(rram_state, data_region,
69
70 if (offset != NULL) {
71 dif_rram_ctrl_device_info_t device_info = dif_rram_ctrl_get_device_info();
72 *offset = base_page_index * device_info.bytes_per_page;
73 }
74 return OK_STATUS();
75}
76
77status_t rram_ctrl_testutils_data_region_setup(
78 dif_rram_ctrl_state_t *rram_state, uint32_t base_page_index,
79 uint32_t data_region, uint32_t region_size, uint32_t *offset) {
80 dif_rram_ctrl_region_properties_t region_properties = {
81 .ecc_en = kMultiBitBool4True,
82 .wr_en = kMultiBitBool4True,
83 .rd_en = kMultiBitBool4True,
84 .scramble_en = kMultiBitBool4False};
85 return rram_ctrl_testutils_data_region_setup_properties(
86 rram_state, base_page_index, data_region, region_size, region_properties,
87 offset);
88}
89
90status_t rram_ctrl_testutils_data_region_scrambled_setup(
91 dif_rram_ctrl_state_t *rram_state, uint32_t base_page_index,
92 uint32_t data_region, uint32_t region_size, uint32_t *offset) {
93 dif_rram_ctrl_region_properties_t region_properties = {
94 .ecc_en = kMultiBitBool4True,
95 .wr_en = kMultiBitBool4True,
96 .rd_en = kMultiBitBool4True,
97 .scramble_en = kMultiBitBool4True};
98 return rram_ctrl_testutils_data_region_setup_properties(
99 rram_state, base_page_index, data_region, region_size, region_properties,
100 offset);
101}
102
103status_t rram_ctrl_testutils_info_region_setup_properties(
104 dif_rram_ctrl_state_t *rram_state, uint32_t page_id,
105 dif_rram_ctrl_region_properties_t region_properties, uint32_t *offset) {
106 dif_rram_ctrl_info_region_t info_region = {.page = page_id};
107
108 TRY(dif_rram_ctrl_set_info_region_properties(rram_state, info_region,
109 region_properties));
110 TRY(dif_rram_ctrl_set_info_region_enablement(rram_state, info_region,
112
113 if (offset != NULL) {
114 dif_rram_ctrl_device_info_t device_info = dif_rram_ctrl_get_device_info();
115 *offset = page_id * device_info.bytes_per_page;
116 }
117 return OK_STATUS();
118}
119
120status_t rram_ctrl_testutils_info_region_setup(
121 dif_rram_ctrl_state_t *rram_state, uint32_t page_id, uint32_t *offset) {
122 dif_rram_ctrl_region_properties_t region_properties = {
123 .ecc_en = kMultiBitBool4True,
124 .wr_en = kMultiBitBool4True,
125 .rd_en = kMultiBitBool4True,
126 .scramble_en = kMultiBitBool4False};
127 return rram_ctrl_testutils_info_region_setup_properties(
128 rram_state, page_id, region_properties, offset);
129}
130
131status_t rram_ctrl_testutils_info_region_scrambled_setup(
132 dif_rram_ctrl_state_t *rram_state, uint32_t page_id, uint32_t *offset) {
133 dif_rram_ctrl_region_properties_t region_properties = {
134 .ecc_en = kMultiBitBool4True,
135 .wr_en = kMultiBitBool4True,
136 .rd_en = kMultiBitBool4True,
137 .scramble_en = kMultiBitBool4True};
138 return rram_ctrl_testutils_info_region_setup_properties(
139 rram_state, page_id, region_properties, offset);
140}
141
142status_t rram_ctrl_testutils_write(
143 dif_rram_ctrl_state_t *rram_state, uint32_t byte_address,
144 const uint32_t *data, dif_rram_ctrl_partition_type_t partition_type,
145 uint32_t word_count) {
146 dif_rram_ctrl_transaction_t transaction = {.byte_address = byte_address,
148 .partition_type = partition_type,
149 .word_count = 0x0};
150 uint32_t words_written = 0;
151 uint32_t word_address = byte_address / sizeof(uint32_t);
152 const uint32_t max_words = (uint32_t)RRAM_CTRL_CONTROL_NUM_MASK + 1;
153
154 while (words_written < word_count) {
155 uint32_t words_remaining = word_count - words_written;
156 uint32_t words_to_write =
157 (words_remaining < max_words) ? words_remaining : max_words;
158 transaction.byte_address = word_address * sizeof(uint32_t);
159 transaction.word_count = words_to_write;
160 TRY(dif_rram_ctrl_start(rram_state, transaction));
161 TRY(dif_rram_ctrl_wr_fifo_push(rram_state, words_to_write,
162 data + words_written));
163 TRY(rram_ctrl_testutils_wait_transaction_end(rram_state));
164 word_address += words_to_write;
165 words_written += words_to_write;
166 }
167 return OK_STATUS();
168}
169
170status_t rram_ctrl_testutils_write_word(
171 dif_rram_ctrl_state_t *rram_state, uint32_t byte_address,
172 const uint32_t *data, dif_rram_ctrl_partition_type_t partition_type) {
173 dif_rram_ctrl_transaction_t transaction = {.byte_address = byte_address,
175 .partition_type = partition_type,
176 .word_count = 0x0};
177 uint32_t word_addr_aligned = byte_address & ~(uintptr_t)0xF;
178 uint32_t word_idx = (byte_address >> 2) % 4;
179
180 uint32_t data_short[4];
181 CHECK_STATUS_OK(rram_ctrl_testutils_read(rram_state, word_addr_aligned,
182 data_short, partition_type, 4, 0));
183 data_short[word_idx] = *data;
184
185 transaction.byte_address = word_addr_aligned;
186 transaction.word_count = 4;
187 TRY(dif_rram_ctrl_start(rram_state, transaction));
188 TRY(dif_rram_ctrl_wr_fifo_push(rram_state, 4, data_short));
189 return rram_ctrl_testutils_wait_transaction_end(rram_state);
190}
191
192status_t rram_ctrl_testutils_read(dif_rram_ctrl_state_t *rram_state,
193 uint32_t byte_address, uint32_t *data_out,
194 dif_rram_ctrl_partition_type_t partition_type,
195 uint32_t word_count, uint32_t delay_micros) {
196 dif_rram_ctrl_transaction_t transaction = {.byte_address = byte_address,
197 .op = kDifRramCtrlOpRead,
198 .partition_type = partition_type,
199 .word_count = word_count};
200
201 // Read Page.
202 TRY(dif_rram_ctrl_start(rram_state, transaction));
203 // Optional delay to allow for read fifo fill testing.
204 busy_spin_micros(delay_micros);
205 TRY(dif_rram_ctrl_read_fifo_pop(rram_state, word_count, data_out));
206 return rram_ctrl_testutils_wait_transaction_end(rram_state);
207}
208
209status_t rram_ctrl_testutils_default_region_access(
210 dif_rram_ctrl_state_t *rram_state, bool rd_en, bool wr_en, bool scramble_en,
211 bool ecc_en) {
212 dif_rram_ctrl_region_properties_t default_properties = {
213 .rd_en = rd_en ? kMultiBitBool4True : kMultiBitBool4False,
214 .wr_en = wr_en ? kMultiBitBool4True : kMultiBitBool4False,
215 .scramble_en = scramble_en ? kMultiBitBool4True : kMultiBitBool4False,
216 .ecc_en = ecc_en ? kMultiBitBool4True : kMultiBitBool4False};
217
218 TRY(dif_rram_ctrl_set_default_region_properties(rram_state,
219 default_properties));
220 return OK_STATUS();
221}
222
223status_t rram_ctrl_testutils_log_faults(
224 const dif_rram_ctrl_state_t *rram_ctrl) {
225 dif_rram_ctrl_faults_t faults = {.lcmgr_memory_protection_error = false};
226 TRY(dif_rram_ctrl_get_faults(rram_ctrl, &faults));
227#define LOG_IF_FIELD_SET(_struct, _field) \
228 if (_struct._field != 0) { \
229 LOG_INFO("rram_ctrl fault status has " #_field); \
230 }
231
232 LOG_IF_FIELD_SET(faults, lcmgr_operation_error);
233 LOG_IF_FIELD_SET(faults, lcmgr_memory_protection_error);
234 LOG_IF_FIELD_SET(faults, lcmgr_read_error);
235 LOG_IF_FIELD_SET(faults, lcmgr_write_error);
236#undef LOG_IF_FIELD_SET
237
238 return OK_STATUS();
239}
240
241static const char *mubi_prop(multi_bit_bool_t val, const char *name) {
242 switch (val) {
243 case kMultiBitBool4True:
244 return name;
245 case kMultiBitBool4False:
246 return "xx";
247 default:
248 return "uu";
249 }
250}
251
252void rram_ctrl_testutils_data_region_print(
253 size_t index, dif_rram_ctrl_data_region_properties_t *p, bool locked) {
254 LOG_INFO("data region n=%u st=%u sz=%u %s-%s-%s-%s %s", index, p->base,
255 p->size, mubi_prop(p->properties.rd_en, "RD"),
256 mubi_prop(p->properties.wr_en, "WR"),
257 mubi_prop(p->properties.scramble_en, "SC"),
258 mubi_prop(p->properties.ecc_en, "EC"), locked ? "LK" : "UN");
259}
260
261void rram_ctrl_testutils_info_region_print(dif_rram_ctrl_info_region_t region,
263 bool locked) {
264 LOG_INFO("info region page=%u %s-%s-%s-%s %s", region.page,
265 mubi_prop(p->rd_en, "RD"), mubi_prop(p->wr_en, "WR"),
266 mubi_prop(p->scramble_en, "SC"), mubi_prop(p->ecc_en, "EC"),
267 locked ? "LK" : "UN");
268}