blob: f5a72b2e8e61c9df49cc682b4890528f5234582d [file] [log] [blame]
Jonny Svärd136810f2021-10-13 16:04:26 +02001/*
2 * Copyright (c) 2019-2021 Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18#include "ethosu_interface.h"
19
20#include "ethosu_config.h"
21#include "ethosu_device.h"
22#include "ethosu_log.h"
23
24#include <assert.h>
25#include <inttypes.h>
26#include <stdbool.h>
27#include <stddef.h>
28#include <stdio.h>
29#include <stdlib.h>
30
31#define BASEP_OFFSET 4
32
33#ifdef ETHOSU65
34#define ADDRESS_BITS 40
35#else
36#define ADDRESS_BITS 32
37#endif
38
39#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1)
40
41#define NPU_CMD_PWR_CLK_MASK (0xC)
42
43struct ethosu_device *ethosu_dev_init(const void *base_address, uint32_t secure_enable, uint32_t privilege_enable)
44{
45 struct ethosu_device *dev = malloc(sizeof(struct ethosu_device));
46 if (!dev)
47 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +010048 LOG_ERR("Failed to allocate memory for Ethos-U device");
Jonny Svärd136810f2021-10-13 16:04:26 +020049 return NULL;
50 }
51
52 dev->reg = (volatile struct NPU_REG *)base_address;
53 dev->secure = secure_enable;
54 dev->privileged = privilege_enable;
55
56 // Make sure the NPU is in a known state
57 if (ethosu_dev_soft_reset(dev) != ETHOSU_SUCCESS)
58 {
59 free(dev);
60 return NULL;
61 }
62
63 return dev;
64}
65
66void ethosu_dev_deinit(struct ethosu_device *dev)
67{
68 free(dev);
69}
70
71enum ethosu_error_codes ethosu_dev_axi_init(struct ethosu_device *dev)
72{
73 struct regioncfg_r rcfg = {0};
74 struct axi_limit0_r l0 = {0};
75 struct axi_limit1_r l1 = {0};
76 struct axi_limit2_r l2 = {0};
77 struct axi_limit3_r l3 = {0};
78
79 dev->reg->QCONFIG.word = NPU_QCONFIG;
80
81 rcfg.region0 = NPU_REGIONCFG_0;
82 rcfg.region1 = NPU_REGIONCFG_1;
83 rcfg.region2 = NPU_REGIONCFG_2;
84 rcfg.region3 = NPU_REGIONCFG_3;
85 rcfg.region4 = NPU_REGIONCFG_4;
86 rcfg.region5 = NPU_REGIONCFG_5;
87 rcfg.region6 = NPU_REGIONCFG_6;
88 rcfg.region7 = NPU_REGIONCFG_7;
89 dev->reg->REGIONCFG.word = rcfg.word;
90
91 l0.max_beats = AXI_LIMIT0_MAX_BEATS_BYTES;
92 l0.memtype = AXI_LIMIT0_MEM_TYPE;
93 l0.max_outstanding_read_m1 = AXI_LIMIT0_MAX_OUTSTANDING_READS - 1;
94 l0.max_outstanding_write_m1 = AXI_LIMIT0_MAX_OUTSTANDING_WRITES - 1;
95
96 l1.max_beats = AXI_LIMIT1_MAX_BEATS_BYTES;
97 l1.memtype = AXI_LIMIT1_MEM_TYPE;
98 l1.max_outstanding_read_m1 = AXI_LIMIT1_MAX_OUTSTANDING_READS - 1;
99 l1.max_outstanding_write_m1 = AXI_LIMIT1_MAX_OUTSTANDING_WRITES - 1;
100
101 l2.max_beats = AXI_LIMIT2_MAX_BEATS_BYTES;
102 l2.memtype = AXI_LIMIT2_MEM_TYPE;
103 l2.max_outstanding_read_m1 = AXI_LIMIT2_MAX_OUTSTANDING_READS - 1;
104 l2.max_outstanding_write_m1 = AXI_LIMIT2_MAX_OUTSTANDING_WRITES - 1;
105
106 l3.max_beats = AXI_LIMIT3_MAX_BEATS_BYTES;
107 l3.memtype = AXI_LIMIT3_MEM_TYPE;
108 l3.max_outstanding_read_m1 = AXI_LIMIT3_MAX_OUTSTANDING_READS - 1;
109 l3.max_outstanding_write_m1 = AXI_LIMIT3_MAX_OUTSTANDING_WRITES - 1;
110
111 dev->reg->AXI_LIMIT0.word = l0.word;
112 dev->reg->AXI_LIMIT1.word = l1.word;
113 dev->reg->AXI_LIMIT2.word = l2.word;
114 dev->reg->AXI_LIMIT3.word = l3.word;
115
116 return ETHOSU_SUCCESS;
117}
118
119enum ethosu_error_codes ethosu_dev_run_command_stream(struct ethosu_device *dev,
120 const uint8_t *cmd_stream_ptr,
121 uint32_t cms_length,
122 const uint64_t *base_addr,
123 int num_base_addr)
124{
125 assert(num_base_addr <= NPU_REG_BASEP_ARRLEN);
126
127 struct cmd_r cmd;
128 uint64_t qbase = (uintptr_t)cmd_stream_ptr + BASE_POINTER_OFFSET;
129 assert(qbase <= ADDRESS_MASK);
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100130 LOG_DEBUG("QBASE=0x%016llx, QSIZE=%u, base_pointer_offset=0x%08x", qbase, cms_length, BASE_POINTER_OFFSET);
Jonny Svärd136810f2021-10-13 16:04:26 +0200131
132 dev->reg->QBASE.word[0] = qbase & 0xffffffff;
133#ifdef ETHOSU65
134 dev->reg->QBASE.word[1] = qbase >> 32;
135#endif
136 dev->reg->QSIZE.word = cms_length;
137
138 for (int i = 0; i < num_base_addr; i++)
139 {
140 uint64_t addr = base_addr[i] + BASE_POINTER_OFFSET;
141 assert(addr <= ADDRESS_MASK);
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100142 LOG_DEBUG("BASEP%d=0x%016llx", i, addr);
Jonny Svärd136810f2021-10-13 16:04:26 +0200143 dev->reg->BASEP[i].word[0] = addr & 0xffffffff;
144#ifdef ETHOSU65
145 dev->reg->BASEP[i].word[1] = addr >> 32;
146#endif
147 }
148
149 cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK;
150 cmd.transition_to_running_state = 1;
151
152 dev->reg->CMD.word = cmd.word;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100153 LOG_DEBUG("CMD=0x%08x", cmd.word);
Jonny Svärd136810f2021-10-13 16:04:26 +0200154
155 return ETHOSU_SUCCESS;
156}
157
158bool ethosu_dev_handle_interrupt(struct ethosu_device *dev)
159{
160 struct cmd_r cmd;
161
162 // Clear interrupt
163 cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK;
164 cmd.clear_irq = 1;
165 dev->reg->CMD.word = cmd.word;
166
167 // If a fault has occured, the NPU needs to be reset
168 if (dev->reg->STATUS.bus_status || dev->reg->STATUS.cmd_parse_error || dev->reg->STATUS.wd_fault ||
Jonny Svärd6d5b0832021-11-30 14:54:07 +0100169 dev->reg->STATUS.ecc_fault || !dev->reg->STATUS.cmd_end_reached)
Jonny Svärd136810f2021-10-13 16:04:26 +0200170 {
Jonny Svärd6d5b0832021-11-30 14:54:07 +0100171 LOG_ERR("NPU fault. status=0x%08x, qread=%" PRIu32 ", cmd_end_reached=%" PRIu32,
172 dev->reg->STATUS.word,
173 dev->reg->QREAD.word,
174 dev->reg->STATUS.cmd_end_reached);
Jonny Svärd136810f2021-10-13 16:04:26 +0200175 ethosu_dev_soft_reset(dev);
176 ethosu_dev_set_clock_and_power(dev, ETHOSU_CLOCK_Q_UNCHANGED, ETHOSU_POWER_Q_DISABLE);
177 return false;
178 }
179
Jonny Svärd6d5b0832021-11-30 14:54:07 +0100180 return true;
Jonny Svärd136810f2021-10-13 16:04:26 +0200181}
182
183bool ethosu_dev_verify_access_state(struct ethosu_device *dev)
184{
185 if (dev->reg->PROT.active_CSL != (dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE) ||
186 dev->reg->PROT.active_CPL != (dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER))
187 {
188 return false;
189 }
190 return true;
191}
192
193enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev)
194{
195 struct reset_r reset;
196
197 reset.word = 0;
198 reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER;
199 reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE;
200
201 // Reset and set security level
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100202 LOG_INFO("Soft reset NPU");
Jonny Svärd136810f2021-10-13 16:04:26 +0200203 dev->reg->RESET.word = reset.word;
204
205 // Wait until reset status indicates that reset has been completed
206 for (int i = 0; i < 100000 && dev->reg->STATUS.reset_status != 0; i++)
207 {
208 }
209
210 if (dev->reg->STATUS.reset_status != 0)
211 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100212 LOG_ERR("Soft reset timed out");
Jonny Svärd136810f2021-10-13 16:04:26 +0200213 return ETHOSU_GENERIC_FAILURE;
214 }
215
216 // Verify that NPU has switched security state and privilege level
217 if (ethosu_dev_verify_access_state(dev) != true)
218 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100219 LOG_ERR("Failed to switch security state and privilege level");
Jonny Svärd136810f2021-10-13 16:04:26 +0200220 return ETHOSU_GENERIC_FAILURE;
221 }
222
223 // Reinitialize AXI settings
224 ethosu_dev_axi_init(dev);
225
226 return ETHOSU_SUCCESS;
227}
228
229void ethosu_dev_get_hw_info(struct ethosu_device *dev, struct ethosu_hw_info *hwinfo)
230{
231 struct config_r cfg;
232 struct id_r id;
233
234 cfg.word = dev->reg->CONFIG.word;
235 id.word = dev->reg->ID.word;
236
237 hwinfo->cfg.cmd_stream_version = cfg.cmd_stream_version;
238 hwinfo->cfg.custom_dma = cfg.custom_dma;
239 hwinfo->cfg.macs_per_cc = cfg.macs_per_cc;
240
241 hwinfo->version.arch_major_rev = id.arch_major_rev;
242 hwinfo->version.arch_minor_rev = id.arch_minor_rev;
243 hwinfo->version.arch_patch_rev = id.arch_patch_rev;
244 hwinfo->version.product_major = id.product_major;
245 hwinfo->version.version_major = id.version_major;
246 hwinfo->version.version_minor = id.version_minor;
247 hwinfo->version.version_status = id.version_status;
248}
249
250enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev,
251 enum ethosu_clock_q_request clock_q,
252 enum ethosu_power_q_request power_q)
253{
254 struct cmd_r cmd = {0};
255 cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK;
256
257 if (power_q != ETHOSU_POWER_Q_UNCHANGED)
258 {
259 cmd.power_q_enable = power_q == ETHOSU_POWER_Q_ENABLE ? 1 : 0;
260 }
261 if (clock_q != ETHOSU_CLOCK_Q_UNCHANGED)
262 {
263 cmd.clock_q_enable = clock_q == ETHOSU_CLOCK_Q_ENABLE ? 1 : 0;
264 }
265
266 dev->reg->CMD.word = cmd.word;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100267 LOG_DEBUG("CMD=0x%08x", cmd.word);
Jonny Svärd136810f2021-10-13 16:04:26 +0200268
269 return ETHOSU_SUCCESS;
270}
271
272bool ethosu_dev_verify_optimizer_config(struct ethosu_device *dev, uint32_t cfg_in, uint32_t id_in)
273{
274 struct config_r *opt_cfg = (struct config_r *)&cfg_in;
275 struct config_r hw_cfg;
276 struct id_r *opt_id = (struct id_r *)&id_in;
277 struct id_r hw_id;
278 bool ret = true;
279
280 hw_cfg.word = dev->reg->CONFIG.word;
281 hw_id.word = dev->reg->ID.word;
282
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100283 LOG_INFO("Optimizer config. cmd_stream_version=%d, macs_per_cc=%d, shram_size=%d, custom_dma=%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200284 opt_cfg->cmd_stream_version,
285 opt_cfg->macs_per_cc,
286 opt_cfg->shram_size,
287 opt_cfg->custom_dma);
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100288 LOG_INFO("Optimizer config. Ethos-U version: %d.%d.%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200289 opt_id->arch_major_rev,
290 opt_id->arch_minor_rev,
291 opt_id->arch_patch_rev);
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100292 LOG_INFO("Ethos-U config. cmd_stream_version=%d, macs_per_cc=%d, shram_size=%d, custom_dma=%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200293 hw_cfg.cmd_stream_version,
294 hw_cfg.macs_per_cc,
295 hw_cfg.shram_size,
296 hw_cfg.custom_dma);
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100297 LOG_INFO("Ethos-U. version=%d.%d.%d", hw_id.arch_major_rev, hw_id.arch_minor_rev, hw_id.arch_patch_rev);
Jonny Svärd136810f2021-10-13 16:04:26 +0200298
299 if (opt_cfg->word != hw_cfg.word)
300 {
301 if (hw_cfg.macs_per_cc != opt_cfg->macs_per_cc)
302 {
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100303 LOG_ERR("NPU config mismatch. npu.macs_per_cc=%d, optimizer.macs_per_cc=%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200304 hw_cfg.macs_per_cc,
305 opt_cfg->macs_per_cc);
306 ret = false;
307 }
308
309 if (hw_cfg.shram_size != opt_cfg->shram_size)
310 {
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100311 LOG_ERR("NPU config mismatch. npu.shram_size=%d, optimizer.shram_size=%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200312 hw_cfg.shram_size,
313 opt_cfg->shram_size);
314 ret = false;
315 }
316
317 if (hw_cfg.cmd_stream_version != opt_cfg->cmd_stream_version)
318 {
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100319 LOG_ERR("NPU config mismatch. npu.cmd_stream_version=%d, optimizer.cmd_stream_version=%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200320 hw_cfg.cmd_stream_version,
321 opt_cfg->cmd_stream_version);
322 ret = false;
323 }
324
325 if (!hw_cfg.custom_dma && opt_cfg->custom_dma)
326 {
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100327 LOG_ERR("NPU config mismatch. npu.custom_dma=%d, optimizer.custom_dma=%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200328 hw_cfg.custom_dma,
329 opt_cfg->custom_dma);
330 ret = false;
331 }
332 }
333
334 if ((hw_id.arch_major_rev != opt_id->arch_major_rev) || (hw_id.arch_minor_rev < opt_id->arch_minor_rev))
335 {
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100336 LOG_ERR("NPU arch mismatch. npu.arch=%d.%d.%d, optimizer.arch=%d.%d.%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200337 hw_id.arch_major_rev,
338 hw_id.arch_minor_rev,
339 hw_id.arch_patch_rev,
340 opt_id->arch_major_rev,
341 opt_id->arch_minor_rev,
342 opt_id->arch_patch_rev);
343 ret = false;
344 }
345
346 return ret;
347}