1 /*
2  * Copyright (c) 2019-2022 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 
19 #include "ethosu_interface.h"
20 
21 #include "ethosu_device.h"
22 #include "ethosu_log.h"
23 
24 #ifdef ETHOSU55
25 #include "ethosu_config_u55.h"
26 #else
27 #include "ethosu_config_u65.h"
28 #endif
29 
30 #include <assert.h>
31 #include <inttypes.h>
32 #include <stdbool.h>
33 #include <stddef.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 
37 #define ETHOSU_PRODUCT_U55 0
38 #define ETHOSU_PRODUCT_U65 1
39 
40 #define BASEP_OFFSET 4
41 
42 #ifdef ETHOSU65
43 #define ADDRESS_BITS 40
44 #else
45 #define ADDRESS_BITS 32
46 #endif
47 
48 #define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1)
49 
50 #define NPU_CMD_PWR_CLK_MASK (0xC)
51 
ethosu_dev_init(const void * base_address,uint32_t secure_enable,uint32_t privilege_enable)52 struct ethosu_device *ethosu_dev_init(const void *base_address, uint32_t secure_enable, uint32_t privilege_enable)
53 {
54     struct ethosu_device *dev = malloc(sizeof(struct ethosu_device));
55     if (!dev)
56     {
57         LOG_ERR("Failed to allocate memory for Ethos-U device");
58         return NULL;
59     }
60 
61     dev->reg        = (volatile struct NPU_REG *)base_address;
62     dev->secure     = secure_enable;
63     dev->privileged = privilege_enable;
64 
65 #ifdef ETHOSU55
66     if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U55)
67 #else
68     if (dev->reg->CONFIG.product != ETHOSU_PRODUCT_U65)
69 #endif
70     {
71         LOG_ERR("Failed to initialize device. Driver has not been compiled for this product");
72         goto err;
73     }
74 
75     // Make sure the NPU is in a known state
76     if (ethosu_dev_soft_reset(dev) != ETHOSU_SUCCESS)
77     {
78         goto err;
79     }
80 
81     return dev;
82 
83 err:
84     free(dev);
85     return NULL;
86 }
87 
ethosu_dev_deinit(struct ethosu_device * dev)88 void ethosu_dev_deinit(struct ethosu_device *dev)
89 {
90     free(dev);
91 }
92 
ethosu_dev_axi_init(struct ethosu_device * dev)93 enum ethosu_error_codes ethosu_dev_axi_init(struct ethosu_device *dev)
94 {
95     struct regioncfg_r rcfg = {0};
96     struct axi_limit0_r l0  = {0};
97     struct axi_limit1_r l1  = {0};
98     struct axi_limit2_r l2  = {0};
99     struct axi_limit3_r l3  = {0};
100 
101     dev->reg->QCONFIG.word = NPU_QCONFIG;
102 
103     rcfg.region0             = NPU_REGIONCFG_0;
104     rcfg.region1             = NPU_REGIONCFG_1;
105     rcfg.region2             = NPU_REGIONCFG_2;
106     rcfg.region3             = NPU_REGIONCFG_3;
107     rcfg.region4             = NPU_REGIONCFG_4;
108     rcfg.region5             = NPU_REGIONCFG_5;
109     rcfg.region6             = NPU_REGIONCFG_6;
110     rcfg.region7             = NPU_REGIONCFG_7;
111     dev->reg->REGIONCFG.word = rcfg.word;
112 
113     l0.max_beats                = AXI_LIMIT0_MAX_BEATS_BYTES;
114     l0.memtype                  = AXI_LIMIT0_MEM_TYPE;
115     l0.max_outstanding_read_m1  = AXI_LIMIT0_MAX_OUTSTANDING_READS - 1;
116     l0.max_outstanding_write_m1 = AXI_LIMIT0_MAX_OUTSTANDING_WRITES - 1;
117 
118     l1.max_beats                = AXI_LIMIT1_MAX_BEATS_BYTES;
119     l1.memtype                  = AXI_LIMIT1_MEM_TYPE;
120     l1.max_outstanding_read_m1  = AXI_LIMIT1_MAX_OUTSTANDING_READS - 1;
121     l1.max_outstanding_write_m1 = AXI_LIMIT1_MAX_OUTSTANDING_WRITES - 1;
122 
123     l2.max_beats                = AXI_LIMIT2_MAX_BEATS_BYTES;
124     l2.memtype                  = AXI_LIMIT2_MEM_TYPE;
125     l2.max_outstanding_read_m1  = AXI_LIMIT2_MAX_OUTSTANDING_READS - 1;
126     l2.max_outstanding_write_m1 = AXI_LIMIT2_MAX_OUTSTANDING_WRITES - 1;
127 
128     l3.max_beats                = AXI_LIMIT3_MAX_BEATS_BYTES;
129     l3.memtype                  = AXI_LIMIT3_MEM_TYPE;
130     l3.max_outstanding_read_m1  = AXI_LIMIT3_MAX_OUTSTANDING_READS - 1;
131     l3.max_outstanding_write_m1 = AXI_LIMIT3_MAX_OUTSTANDING_WRITES - 1;
132 
133     dev->reg->AXI_LIMIT0.word = l0.word;
134     dev->reg->AXI_LIMIT1.word = l1.word;
135     dev->reg->AXI_LIMIT2.word = l2.word;
136     dev->reg->AXI_LIMIT3.word = l3.word;
137 
138     return ETHOSU_SUCCESS;
139 }
140 
ethosu_dev_run_command_stream(struct ethosu_device * dev,const uint8_t * cmd_stream_ptr,uint32_t cms_length,const uint64_t * base_addr,int num_base_addr)141 void ethosu_dev_run_command_stream(struct ethosu_device *dev,
142                                    const uint8_t *cmd_stream_ptr,
143                                    uint32_t cms_length,
144                                    const uint64_t *base_addr,
145                                    int num_base_addr)
146 {
147     assert(num_base_addr <= NPU_REG_BASEP_ARRLEN);
148 
149     struct cmd_r cmd;
150     uint64_t qbase = (uintptr_t)cmd_stream_ptr + BASE_POINTER_OFFSET;
151     assert(qbase <= ADDRESS_MASK);
152     LOG_DEBUG("QBASE=0x%016llx, QSIZE=%u, base_pointer_offset=0x%08x", qbase, cms_length, BASE_POINTER_OFFSET);
153 
154     dev->reg->QBASE.word[0] = qbase & 0xffffffff;
155 #ifdef ETHOSU65
156     dev->reg->QBASE.word[1] = qbase >> 32;
157 #endif
158     dev->reg->QSIZE.word = cms_length;
159 
160     for (int i = 0; i < num_base_addr; i++)
161     {
162         uint64_t addr = base_addr[i] + BASE_POINTER_OFFSET;
163         assert(addr <= ADDRESS_MASK);
164         LOG_DEBUG("BASEP%d=0x%016llx", i, addr);
165         dev->reg->BASEP[i].word[0] = addr & 0xffffffff;
166 #ifdef ETHOSU65
167         dev->reg->BASEP[i].word[1] = addr >> 32;
168 #endif
169     }
170 
171     cmd.word                        = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK;
172     cmd.transition_to_running_state = 1;
173 
174     dev->reg->CMD.word = cmd.word;
175     LOG_DEBUG("CMD=0x%08x", cmd.word);
176 }
177 
ethosu_dev_print_err_status(struct ethosu_device * dev)178 void ethosu_dev_print_err_status(struct ethosu_device *dev)
179 {
180     LOG_ERR("NPU status=0x%08" PRIx32 ", qread=%" PRIu32 ", cmd_end_reached=%d",
181             dev->reg->STATUS.word,
182             dev->reg->QREAD.word,
183             dev->reg->STATUS.cmd_end_reached);
184 }
185 
ethosu_dev_handle_interrupt(struct ethosu_device * dev)186 bool ethosu_dev_handle_interrupt(struct ethosu_device *dev)
187 {
188     struct cmd_r cmd;
189 
190     // Clear interrupt
191     cmd.word           = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK;
192     cmd.clear_irq      = 1;
193     dev->reg->CMD.word = cmd.word;
194 
195     // If a fault has occured, the NPU needs to be reset
196     if (dev->reg->STATUS.bus_status || dev->reg->STATUS.cmd_parse_error || dev->reg->STATUS.wd_fault ||
197         dev->reg->STATUS.ecc_fault || !dev->reg->STATUS.cmd_end_reached)
198     {
199         return false;
200     }
201 
202     return true;
203 }
204 
ethosu_dev_verify_access_state(struct ethosu_device * dev)205 bool ethosu_dev_verify_access_state(struct ethosu_device *dev)
206 {
207     if (dev->reg->PROT.active_CSL != (dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE) ||
208         dev->reg->PROT.active_CPL != (dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER))
209     {
210         return false;
211     }
212     return true;
213 }
214 
ethosu_dev_soft_reset(struct ethosu_device * dev)215 enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev)
216 {
217     // Note that after a soft-reset, the NPU is unconditionally
218     // powered until the next CMD gets written.
219 
220     struct reset_r reset;
221 
222     reset.word        = 0;
223     reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER;
224     reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE;
225 
226     // Reset and set security level
227     LOG_INFO("Soft reset NPU");
228     dev->reg->RESET.word = reset.word;
229 
230     // Wait until reset status indicates that reset has been completed
231     for (int i = 0; i < 100000 && dev->reg->STATUS.reset_status != 0; i++)
232     {
233     }
234 
235     if (dev->reg->STATUS.reset_status != 0)
236     {
237         LOG_ERR("Soft reset timed out");
238         return ETHOSU_GENERIC_FAILURE;
239     }
240 
241     // Verify that NPU has switched security state and privilege level
242     if (ethosu_dev_verify_access_state(dev) != true)
243     {
244         LOG_ERR("Failed to switch security state and privilege level");
245         return ETHOSU_GENERIC_FAILURE;
246     }
247 
248     // Reinitialize AXI settings
249     ethosu_dev_axi_init(dev);
250 
251     return ETHOSU_SUCCESS;
252 }
253 
ethosu_dev_get_hw_info(struct ethosu_device * dev,struct ethosu_hw_info * hwinfo)254 void ethosu_dev_get_hw_info(struct ethosu_device *dev, struct ethosu_hw_info *hwinfo)
255 {
256     struct config_r cfg;
257     struct id_r id;
258 
259     cfg.word = dev->reg->CONFIG.word;
260     id.word  = dev->reg->ID.word;
261 
262     hwinfo->cfg.cmd_stream_version = cfg.cmd_stream_version;
263     hwinfo->cfg.custom_dma         = cfg.custom_dma;
264     hwinfo->cfg.macs_per_cc        = cfg.macs_per_cc;
265 
266     hwinfo->version.arch_major_rev = id.arch_major_rev;
267     hwinfo->version.arch_minor_rev = id.arch_minor_rev;
268     hwinfo->version.arch_patch_rev = id.arch_patch_rev;
269     hwinfo->version.product_major  = id.product_major;
270     hwinfo->version.version_major  = id.version_major;
271     hwinfo->version.version_minor  = id.version_minor;
272     hwinfo->version.version_status = id.version_status;
273 }
274 
ethosu_dev_set_clock_and_power(struct ethosu_device * dev,enum ethosu_clock_q_request clock_q,enum ethosu_power_q_request power_q)275 enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev,
276                                                        enum ethosu_clock_q_request clock_q,
277                                                        enum ethosu_power_q_request power_q)
278 {
279     struct cmd_r cmd = {0};
280     cmd.word         = dev->reg->CMD.word & NPU_CMD_PWR_CLK_MASK;
281 
282     if (power_q != ETHOSU_POWER_Q_UNCHANGED)
283     {
284         cmd.power_q_enable = power_q == ETHOSU_POWER_Q_ENABLE ? 1 : 0;
285     }
286     if (clock_q != ETHOSU_CLOCK_Q_UNCHANGED)
287     {
288         cmd.clock_q_enable = clock_q == ETHOSU_CLOCK_Q_ENABLE ? 1 : 0;
289     }
290 
291     dev->reg->CMD.word = cmd.word;
292     LOG_DEBUG("CMD=0x%08x", cmd.word);
293 
294     return ETHOSU_SUCCESS;
295 }
296 
ethosu_dev_verify_optimizer_config(struct ethosu_device * dev,uint32_t cfg_in,uint32_t id_in)297 bool ethosu_dev_verify_optimizer_config(struct ethosu_device *dev, uint32_t cfg_in, uint32_t id_in)
298 {
299     struct config_r *opt_cfg = (struct config_r *)&cfg_in;
300     struct config_r hw_cfg;
301     struct id_r *opt_id = (struct id_r *)&id_in;
302     struct id_r hw_id;
303     bool ret = true;
304 
305     hw_cfg.word = dev->reg->CONFIG.word;
306     hw_id.word  = dev->reg->ID.word;
307 
308     LOG_INFO("Optimizer config. product=%d, cmd_stream_version=%d, macs_per_cc=%d, shram_size=%d, custom_dma=%d",
309              opt_cfg->product,
310              opt_cfg->cmd_stream_version,
311              opt_cfg->macs_per_cc,
312              opt_cfg->shram_size,
313              opt_cfg->custom_dma);
314     LOG_INFO("Optimizer config. arch version: %d.%d.%d",
315              opt_id->arch_major_rev,
316              opt_id->arch_minor_rev,
317              opt_id->arch_patch_rev);
318     LOG_INFO("Ethos-U config. product=%d, cmd_stream_version=%d, macs_per_cc=%d, shram_size=%d, custom_dma=%d",
319              hw_cfg.product,
320              hw_cfg.cmd_stream_version,
321              hw_cfg.macs_per_cc,
322              hw_cfg.shram_size,
323              hw_cfg.custom_dma);
324     LOG_INFO("Ethos-U. arch version=%d.%d.%d", hw_id.arch_major_rev, hw_id.arch_minor_rev, hw_id.arch_patch_rev);
325 
326     if (opt_cfg->word != hw_cfg.word)
327     {
328         if (hw_cfg.product != opt_cfg->product)
329         {
330             LOG_ERR("NPU config mismatch. npu.product=%d, optimizer.product=%d", hw_cfg.product, opt_cfg->product);
331             ret = false;
332         }
333 
334         if (hw_cfg.macs_per_cc != opt_cfg->macs_per_cc)
335         {
336             LOG_ERR("NPU config mismatch. npu.macs_per_cc=%d, optimizer.macs_per_cc=%d",
337                     hw_cfg.macs_per_cc,
338                     opt_cfg->macs_per_cc);
339             ret = false;
340         }
341 
342         if (hw_cfg.cmd_stream_version != opt_cfg->cmd_stream_version)
343         {
344             LOG_ERR("NPU config mismatch. npu.cmd_stream_version=%d, optimizer.cmd_stream_version=%d",
345                     hw_cfg.cmd_stream_version,
346                     opt_cfg->cmd_stream_version);
347             ret = false;
348         }
349 
350         if (!hw_cfg.custom_dma && opt_cfg->custom_dma)
351         {
352             LOG_ERR("NPU config mismatch. npu.custom_dma=%d, optimizer.custom_dma=%d",
353                     hw_cfg.custom_dma,
354                     opt_cfg->custom_dma);
355             ret = false;
356         }
357     }
358 
359     if ((hw_id.arch_major_rev != opt_id->arch_major_rev) || (hw_id.arch_minor_rev < opt_id->arch_minor_rev))
360     {
361         LOG_ERR("NPU arch mismatch. npu.arch=%d.%d.%d, optimizer.arch=%d.%d.%d",
362                 hw_id.arch_major_rev,
363                 hw_id.arch_minor_rev,
364                 hw_id.arch_patch_rev,
365                 opt_id->arch_major_rev,
366                 opt_id->arch_minor_rev,
367                 opt_id->arch_patch_rev);
368         ret = false;
369     }
370 
371     return ret;
372 }
373