blob: f16f9f837012e348fb9d81165792458cd36fceb1 [file] [log] [blame]
Jonny Svärd136810f2021-10-13 16:04:26 +02001/*
Jonny Svärdd1750ec2022-01-04 10:59:16 +01002 * Copyright (c) 2019-2022 Arm Limited. All rights reserved.
Jonny Svärd136810f2021-10-13 16:04:26 +02003 *
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 */
Jonny Svärdd1750ec2022-01-04 10:59:16 +010018
Jonny Svärd136810f2021-10-13 16:04:26 +020019#include "ethosu_interface.h"
20
21#include "ethosu_config.h"
22#include "ethosu_device.h"
23#include "ethosu_log.h"
24
25#include <assert.h>
26#include <inttypes.h>
27#include <stdbool.h>
28#include <stddef.h>
29#include <stdio.h>
30#include <stdlib.h>
31
Jonny Svärdd1750ec2022-01-04 10:59:16 +010032#define ETHOSU_PRODUCT_U55 0
33#define ETHOSU_PRODUCT_U65 1
34
Jonny Svärd136810f2021-10-13 16:04:26 +020035#define BASEP_OFFSET 4
36
37#ifdef ETHOSU65
38#define ADDRESS_BITS 40
39#else
40#define ADDRESS_BITS 32
41#endif
42
43#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1)
44
45#define NPU_CMD_PWR_CLK_MASK (0xC)
46
47struct ethosu_device *ethosu_dev_init(const void *base_address, uint32_t secure_enable, uint32_t privilege_enable)
48{
49 struct ethosu_device *dev = malloc(sizeof(struct ethosu_device));
50 if (!dev)
51 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +010052 LOG_ERR("Failed to allocate memory for Ethos-U device");
Jonny Svärd136810f2021-10-13 16:04:26 +020053 return NULL;
54 }
55
56 dev->reg = (volatile struct NPU_REG *)base_address;
57 dev->secure = secure_enable;
58 dev->privileged = privilege_enable;
59
Jonny Svärdd1750ec2022-01-04 10:59:16 +010060#ifdef ETHOSU55
61 if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U55)
62#else
63 if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U65)
64#endif
65 {
66 LOG_ERR("Failed to initialize device. Driver has not been compiled for this product");
67 goto err;
68 }
69
Jonny Svärd136810f2021-10-13 16:04:26 +020070 // Make sure the NPU is in a known state
71 if (ethosu_dev_soft_reset(dev) != ETHOSU_SUCCESS)
72 {
Jonny Svärdd1750ec2022-01-04 10:59:16 +010073 goto err;
Jonny Svärd136810f2021-10-13 16:04:26 +020074 }
75
76 return dev;
Jonny Svärdd1750ec2022-01-04 10:59:16 +010077
78err:
79 free(dev);
80 return NULL;
Jonny Svärd136810f2021-10-13 16:04:26 +020081}
82
83void ethosu_dev_deinit(struct ethosu_device *dev)
84{
85 free(dev);
86}
87
88enum ethosu_error_codes ethosu_dev_axi_init(struct ethosu_device *dev)
89{
90 struct regioncfg_r rcfg = {0};
91 struct axi_limit0_r l0 = {0};
92 struct axi_limit1_r l1 = {0};
93 struct axi_limit2_r l2 = {0};
94 struct axi_limit3_r l3 = {0};
95
96 dev->reg->QCONFIG.word = NPU_QCONFIG;
97
98 rcfg.region0 = NPU_REGIONCFG_0;
99 rcfg.region1 = NPU_REGIONCFG_1;
100 rcfg.region2 = NPU_REGIONCFG_2;
101 rcfg.region3 = NPU_REGIONCFG_3;
102 rcfg.region4 = NPU_REGIONCFG_4;
103 rcfg.region5 = NPU_REGIONCFG_5;
104 rcfg.region6 = NPU_REGIONCFG_6;
105 rcfg.region7 = NPU_REGIONCFG_7;
106 dev->reg->REGIONCFG.word = rcfg.word;
107
108 l0.max_beats = AXI_LIMIT0_MAX_BEATS_BYTES;
109 l0.memtype = AXI_LIMIT0_MEM_TYPE;
110 l0.max_outstanding_read_m1 = AXI_LIMIT0_MAX_OUTSTANDING_READS - 1;
111 l0.max_outstanding_write_m1 = AXI_LIMIT0_MAX_OUTSTANDING_WRITES - 1;
112
113 l1.max_beats = AXI_LIMIT1_MAX_BEATS_BYTES;
114 l1.memtype = AXI_LIMIT1_MEM_TYPE;
115 l1.max_outstanding_read_m1 = AXI_LIMIT1_MAX_OUTSTANDING_READS - 1;
116 l1.max_outstanding_write_m1 = AXI_LIMIT1_MAX_OUTSTANDING_WRITES - 1;
117
118 l2.max_beats = AXI_LIMIT2_MAX_BEATS_BYTES;
119 l2.memtype = AXI_LIMIT2_MEM_TYPE;
120 l2.max_outstanding_read_m1 = AXI_LIMIT2_MAX_OUTSTANDING_READS - 1;
121 l2.max_outstanding_write_m1 = AXI_LIMIT2_MAX_OUTSTANDING_WRITES - 1;
122
123 l3.max_beats = AXI_LIMIT3_MAX_BEATS_BYTES;
124 l3.memtype = AXI_LIMIT3_MEM_TYPE;
125 l3.max_outstanding_read_m1 = AXI_LIMIT3_MAX_OUTSTANDING_READS - 1;
126 l3.max_outstanding_write_m1 = AXI_LIMIT3_MAX_OUTSTANDING_WRITES - 1;
127
128 dev->reg->AXI_LIMIT0.word = l0.word;
129 dev->reg->AXI_LIMIT1.word = l1.word;
130 dev->reg->AXI_LIMIT2.word = l2.word;
131 dev->reg->AXI_LIMIT3.word = l3.word;
132
133 return ETHOSU_SUCCESS;
134}
135
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100136void ethosu_dev_run_command_stream(struct ethosu_device *dev,
137 const uint8_t *cmd_stream_ptr,
138 uint32_t cms_length,
139 const uint64_t *base_addr,
140 int num_base_addr)
Jonny Svärd136810f2021-10-13 16:04:26 +0200141{
142 assert(num_base_addr <= NPU_REG_BASEP_ARRLEN);
143
144 struct cmd_r cmd;
145 uint64_t qbase = (uintptr_t)cmd_stream_ptr + BASE_POINTER_OFFSET;
146 assert(qbase <= ADDRESS_MASK);
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100147 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 +0200148
149 dev->reg->QBASE.word[0] = qbase & 0xffffffff;
150#ifdef ETHOSU65
151 dev->reg->QBASE.word[1] = qbase >> 32;
152#endif
153 dev->reg->QSIZE.word = cms_length;
154
155 for (int i = 0; i < num_base_addr; i++)
156 {
157 uint64_t addr = base_addr[i] + BASE_POINTER_OFFSET;
158 assert(addr <= ADDRESS_MASK);
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100159 LOG_DEBUG("BASEP%d=0x%016llx", i, addr);
Jonny Svärd136810f2021-10-13 16:04:26 +0200160 dev->reg->BASEP[i].word[0] = addr & 0xffffffff;
161#ifdef ETHOSU65
162 dev->reg->BASEP[i].word[1] = addr >> 32;
163#endif
164 }
165
166 cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK;
167 cmd.transition_to_running_state = 1;
168
169 dev->reg->CMD.word = cmd.word;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100170 LOG_DEBUG("CMD=0x%08x", cmd.word);
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100171}
Jonny Svärd136810f2021-10-13 16:04:26 +0200172
Jonny Svärd1a3bb922022-02-25 16:28:21 +0100173void ethosu_dev_print_err_status(struct ethosu_device *dev)
174{
175 LOG_ERR("NPU status=0x%08" PRIx32 ", qread=%" PRIu32 ", cmd_end_reached=%d",
176 dev->reg->STATUS.word,
177 dev->reg->QREAD.word,
178 dev->reg->STATUS.cmd_end_reached);
Jonny Svärd136810f2021-10-13 16:04:26 +0200179}
180
181bool ethosu_dev_handle_interrupt(struct ethosu_device *dev)
182{
183 struct cmd_r cmd;
184
185 // Clear interrupt
186 cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK;
187 cmd.clear_irq = 1;
188 dev->reg->CMD.word = cmd.word;
189
190 // If a fault has occured, the NPU needs to be reset
191 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 +0100192 dev->reg->STATUS.ecc_fault || !dev->reg->STATUS.cmd_end_reached)
Jonny Svärd136810f2021-10-13 16:04:26 +0200193 {
Jonny Svärd136810f2021-10-13 16:04:26 +0200194 return false;
195 }
196
Jonny Svärd6d5b0832021-11-30 14:54:07 +0100197 return true;
Jonny Svärd136810f2021-10-13 16:04:26 +0200198}
199
200bool ethosu_dev_verify_access_state(struct ethosu_device *dev)
201{
202 if (dev->reg->PROT.active_CSL != (dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE) ||
203 dev->reg->PROT.active_CPL != (dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER))
204 {
205 return false;
206 }
207 return true;
208}
209
210enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev)
211{
Jonny Svärd301399d2022-04-26 18:31:24 +0200212 // Note that after a soft-reset, the NPU is unconditionally
213 // powered until the next CMD gets written.
214
Jonny Svärd136810f2021-10-13 16:04:26 +0200215 struct reset_r reset;
216
217 reset.word = 0;
218 reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER;
219 reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE;
220
221 // Reset and set security level
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100222 LOG_INFO("Soft reset NPU");
Jonny Svärd136810f2021-10-13 16:04:26 +0200223 dev->reg->RESET.word = reset.word;
224
225 // Wait until reset status indicates that reset has been completed
226 for (int i = 0; i < 100000 && dev->reg->STATUS.reset_status != 0; i++)
227 {
228 }
229
230 if (dev->reg->STATUS.reset_status != 0)
231 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100232 LOG_ERR("Soft reset timed out");
Jonny Svärd136810f2021-10-13 16:04:26 +0200233 return ETHOSU_GENERIC_FAILURE;
234 }
235
236 // Verify that NPU has switched security state and privilege level
237 if (ethosu_dev_verify_access_state(dev) != true)
238 {
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100239 LOG_ERR("Failed to switch security state and privilege level");
Jonny Svärd136810f2021-10-13 16:04:26 +0200240 return ETHOSU_GENERIC_FAILURE;
241 }
242
243 // Reinitialize AXI settings
244 ethosu_dev_axi_init(dev);
245
246 return ETHOSU_SUCCESS;
247}
248
249void ethosu_dev_get_hw_info(struct ethosu_device *dev, struct ethosu_hw_info *hwinfo)
250{
251 struct config_r cfg;
252 struct id_r id;
253
254 cfg.word = dev->reg->CONFIG.word;
255 id.word = dev->reg->ID.word;
256
257 hwinfo->cfg.cmd_stream_version = cfg.cmd_stream_version;
258 hwinfo->cfg.custom_dma = cfg.custom_dma;
259 hwinfo->cfg.macs_per_cc = cfg.macs_per_cc;
260
261 hwinfo->version.arch_major_rev = id.arch_major_rev;
262 hwinfo->version.arch_minor_rev = id.arch_minor_rev;
263 hwinfo->version.arch_patch_rev = id.arch_patch_rev;
264 hwinfo->version.product_major = id.product_major;
265 hwinfo->version.version_major = id.version_major;
266 hwinfo->version.version_minor = id.version_minor;
267 hwinfo->version.version_status = id.version_status;
268}
269
270enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev,
271 enum ethosu_clock_q_request clock_q,
272 enum ethosu_power_q_request power_q)
273{
274 struct cmd_r cmd = {0};
275 cmd.word = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK;
276
277 if (power_q != ETHOSU_POWER_Q_UNCHANGED)
278 {
279 cmd.power_q_enable = power_q == ETHOSU_POWER_Q_ENABLE ? 1 : 0;
280 }
281 if (clock_q != ETHOSU_CLOCK_Q_UNCHANGED)
282 {
283 cmd.clock_q_enable = clock_q == ETHOSU_CLOCK_Q_ENABLE ? 1 : 0;
284 }
285
286 dev->reg->CMD.word = cmd.word;
Kristofer Jonsson089a3472021-11-12 12:52:07 +0100287 LOG_DEBUG("CMD=0x%08x", cmd.word);
Jonny Svärd136810f2021-10-13 16:04:26 +0200288
289 return ETHOSU_SUCCESS;
290}
291
292bool ethosu_dev_verify_optimizer_config(struct ethosu_device *dev, uint32_t cfg_in, uint32_t id_in)
293{
294 struct config_r *opt_cfg = (struct config_r *)&cfg_in;
295 struct config_r hw_cfg;
296 struct id_r *opt_id = (struct id_r *)&id_in;
297 struct id_r hw_id;
298 bool ret = true;
299
300 hw_cfg.word = dev->reg->CONFIG.word;
301 hw_id.word = dev->reg->ID.word;
302
Jonny Svärdd1750ec2022-01-04 10:59:16 +0100303 LOG_INFO("Optimizer config. product=%d, cmd_stream_version=%d, macs_per_cc=%d, shram_size=%d, custom_dma=%d",
304 opt_cfg->product,
Jonny Svärd136810f2021-10-13 16:04:26 +0200305 opt_cfg->cmd_stream_version,
306 opt_cfg->macs_per_cc,
307 opt_cfg->shram_size,
308 opt_cfg->custom_dma);
Jonny Svärdd1750ec2022-01-04 10:59:16 +0100309 LOG_INFO("Optimizer config. arch version: %d.%d.%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200310 opt_id->arch_major_rev,
311 opt_id->arch_minor_rev,
312 opt_id->arch_patch_rev);
Jonny Svärdd1750ec2022-01-04 10:59:16 +0100313 LOG_INFO("Ethos-U config. product=%d, cmd_stream_version=%d, macs_per_cc=%d, shram_size=%d, custom_dma=%d",
314 hw_cfg.product,
Jonny Svärd136810f2021-10-13 16:04:26 +0200315 hw_cfg.cmd_stream_version,
316 hw_cfg.macs_per_cc,
317 hw_cfg.shram_size,
318 hw_cfg.custom_dma);
Jonny Svärdd1750ec2022-01-04 10:59:16 +0100319 LOG_INFO("Ethos-U. arch 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 +0200320
321 if (opt_cfg->word != hw_cfg.word)
322 {
Jonny Svärdd1750ec2022-01-04 10:59:16 +0100323 if (hw_cfg.product != opt_cfg->product)
324 {
325 LOG_ERR("NPU config mismatch. npu.product=%d, optimizer.product=%d", hw_cfg.product, opt_cfg->product);
326 ret = false;
327 }
328
Jonny Svärd136810f2021-10-13 16:04:26 +0200329 if (hw_cfg.macs_per_cc != opt_cfg->macs_per_cc)
330 {
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100331 LOG_ERR("NPU config mismatch. npu.macs_per_cc=%d, optimizer.macs_per_cc=%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200332 hw_cfg.macs_per_cc,
333 opt_cfg->macs_per_cc);
334 ret = false;
335 }
336
Jonny Svärd136810f2021-10-13 16:04:26 +0200337 if (hw_cfg.cmd_stream_version != opt_cfg->cmd_stream_version)
338 {
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100339 LOG_ERR("NPU config mismatch. npu.cmd_stream_version=%d, optimizer.cmd_stream_version=%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200340 hw_cfg.cmd_stream_version,
341 opt_cfg->cmd_stream_version);
342 ret = false;
343 }
344
345 if (!hw_cfg.custom_dma && opt_cfg->custom_dma)
346 {
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100347 LOG_ERR("NPU config mismatch. npu.custom_dma=%d, optimizer.custom_dma=%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200348 hw_cfg.custom_dma,
349 opt_cfg->custom_dma);
350 ret = false;
351 }
352 }
353
354 if ((hw_id.arch_major_rev != opt_id->arch_major_rev) || (hw_id.arch_minor_rev < opt_id->arch_minor_rev))
355 {
Kristofer Jonsson1975b8d2021-11-26 16:15:44 +0100356 LOG_ERR("NPU arch mismatch. npu.arch=%d.%d.%d, optimizer.arch=%d.%d.%d",
Jonny Svärd136810f2021-10-13 16:04:26 +0200357 hw_id.arch_major_rev,
358 hw_id.arch_minor_rev,
359 hw_id.arch_patch_rev,
360 opt_id->arch_major_rev,
361 opt_id->arch_minor_rev,
362 opt_id->arch_patch_rev);
363 ret = false;
364 }
365
366 return ret;
367}