blob: 093094885d60fe98fc09934f65213f37c6e31a01 [file] [log] [blame]
Jonny Svärda830f172021-06-07 16:57:00 +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 "ethosu55_interface.h"
19
20#include "ethosu_common.h"
21#include "ethosu_config.h"
22#include "ethosu_device.h"
Anton Moberg6eab40b2021-07-07 11:43:51 +020023#include "ethosu_log.h"
Jonny Svärda830f172021-06-07 16:57:00 +020024
25#include <assert.h>
26#include <stddef.h>
27#include <stdio.h>
28
29#define BASEP_OFFSET 4
30#define REG_OFFSET 4
31#define BYTES_1KB 1024
32
33#define ADDRESS_BITS 48
34#define ADDRESS_MASK ((1ull << ADDRESS_BITS) - 1)
35
36enum ethosu_error_codes ethosu_dev_init(struct ethosu_device *dev,
37 const void *base_address,
38 uint32_t secure_enable,
39 uint32_t privilege_enable)
40{
41 dev->base_address = (volatile uintptr_t)base_address;
42 dev->secure = secure_enable;
43 dev->privileged = privilege_enable;
44
45 ethosu_dev_save_pmu_config(dev);
46
47 return ETHOSU_SUCCESS;
48}
49
50enum ethosu_error_codes ethosu_dev_get_id(struct ethosu_device *dev, struct ethosu_id *id)
51{
52 struct id_r _id;
53
54 _id.word = ethosu_dev_read_reg(dev, NPU_REG_ID);
55
56 id->version_status = _id.version_status;
57 id->version_minor = _id.version_minor;
58 id->version_major = _id.version_major;
59 id->product_major = _id.product_major;
60 id->arch_patch_rev = _id.arch_patch_rev;
61 id->arch_minor_rev = _id.arch_minor_rev;
62 id->arch_major_rev = _id.arch_major_rev;
63
64 return ETHOSU_SUCCESS;
65}
66
67enum ethosu_error_codes ethosu_dev_get_config(struct ethosu_device *dev, struct ethosu_config *config)
68{
69 struct config_r cfg = {.word = 0};
70
71 cfg.word = ethosu_dev_read_reg(dev, NPU_REG_CONFIG);
72
73 config->macs_per_cc = cfg.macs_per_cc;
74 config->cmd_stream_version = cfg.cmd_stream_version;
75 config->shram_size = cfg.shram_size;
76 config->custom_dma = cfg.custom_dma;
77
78 return ETHOSU_SUCCESS;
79}
80
81enum ethosu_error_codes ethosu_dev_run_command_stream(struct ethosu_device *dev,
82 const uint8_t *cmd_stream_ptr,
83 uint32_t cms_length,
84 const uint64_t *base_addr,
85 int num_base_addr)
86{
87 assert(num_base_addr <= ETHOSU_BASEP_INDEXES);
88
89 uint64_t qbase = (uintptr_t)cmd_stream_ptr + BASE_POINTER_OFFSET;
90 assert(qbase <= ADDRESS_MASK);
91 LOG_DEBUG("QBASE=0x%016llx, QSIZE=%u, base_pointer_offset=0x%08x\n", qbase, cms_length, BASE_POINTER_OFFSET);
92
93 ethosu_dev_write_reg(dev, NPU_REG_QBASE0, qbase & 0xffffffff);
94 ethosu_dev_write_reg(dev, NPU_REG_QBASE1, qbase >> 32);
95 ethosu_dev_write_reg(dev, NPU_REG_QSIZE, cms_length);
96
97 for (int i = 0; i < num_base_addr; i++)
98 {
99 uint64_t addr = base_addr[i] + BASE_POINTER_OFFSET;
100 assert(addr <= ADDRESS_MASK);
101 LOG_DEBUG("BASEP%d=0x%016llx\n", i, addr);
102 ethosu_dev_write_reg(dev, NPU_REG_BASEP0 + (2 * i) * BASEP_OFFSET, addr & 0xffffffff);
103 ethosu_dev_write_reg(dev, NPU_REG_BASEP0 + (2 * i + 1) * BASEP_OFFSET, addr >> 32);
104 }
105
106 return ethosu_dev_set_command_run(dev);
107}
108
109enum ethosu_error_codes ethosu_dev_is_irq_raised(struct ethosu_device *dev, uint8_t *irq_raised)
110{
111 struct status_r status;
112
113 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
114
115 if (status.irq_raised == 1)
116 {
117 *irq_raised = 1;
118 }
119 else
120 {
121 *irq_raised = 0;
122 }
123
124 return ETHOSU_SUCCESS;
125}
126
127enum ethosu_error_codes ethosu_dev_clear_irq_status(struct ethosu_device *dev)
128{
129 struct cmd_r oldcmd;
130 struct cmd_r cmd;
131
132 oldcmd.word = ethosu_dev_read_reg(dev, NPU_REG_CMD);
133
134 cmd.word = 0;
135 cmd.clear_irq = 1;
136 cmd.clock_q_enable = oldcmd.clock_q_enable;
137 cmd.power_q_enable = oldcmd.power_q_enable;
138 ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
139 LOG_DEBUG("CMD=0x%08x\n", cmd.word);
140
141 return ETHOSU_SUCCESS;
142}
143
144enum ethosu_error_codes ethosu_dev_soft_reset(struct ethosu_device *dev)
145{
146 enum ethosu_error_codes return_code = ETHOSU_SUCCESS;
147 struct reset_r reset;
148 struct prot_r prot;
149
150 reset.word = 0;
151 reset.pending_CPL = dev->privileged ? PRIVILEGE_LEVEL_PRIVILEGED : PRIVILEGE_LEVEL_USER;
152 reset.pending_CSL = dev->secure ? SECURITY_LEVEL_SECURE : SECURITY_LEVEL_NON_SECURE;
153
154 // Reset and set security level
155 LOG_INFO("Soft reset NPU\n");
156 ethosu_dev_write_reg(dev, NPU_REG_RESET, reset.word);
157
158 // Wait for reset to complete
159 return_code = ethosu_dev_wait_for_reset(dev);
160 if (return_code != ETHOSU_SUCCESS)
161 {
162 LOG_ERR("Soft reset timed out\n");
163 return return_code;
164 }
165
166 // Verify that NPU has switched security state and privilege level
167 prot.word = ethosu_dev_read_reg(dev, NPU_REG_PROT);
168 if (prot.active_CPL != reset.pending_CPL || prot.active_CSL != reset.pending_CSL)
169 {
170 LOG_ERR("Failed to switch security state and privilege level\n");
171 // Register access not permitted
172 return ETHOSU_GENERIC_FAILURE;
173 }
174
175 // Save the prot register
176 dev->proto = prot.word;
177
178 // Soft reset will clear the PMU configuration and counters. The shadow PMU counters
179 // are cleared by saving the PMU counters to ram, which will read back zeros.
180 // The PMU configuration will be restored in the invoke function after power save
181 // has been disabled.
182 ethosu_dev_save_pmu_counters(dev);
183
184 return return_code;
185}
186
187enum ethosu_error_codes ethosu_dev_wait_for_reset(struct ethosu_device *dev)
188{
189 struct status_r status;
190
191 // Wait until reset status indicates that reset has been completed
192 for (int i = 0; i < 100000; i++)
193 {
194 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
195 if (0 == status.reset_status)
196 {
197 break;
198 }
199 }
200
201 if (1 == status.reset_status)
202 {
203 return ETHOSU_GENERIC_FAILURE;
204 }
205
206 return ETHOSU_SUCCESS;
207}
208
209enum ethosu_error_codes ethosu_dev_read_apb_reg(struct ethosu_device *dev,
210 uint32_t start_address,
211 uint16_t num_reg,
212 uint32_t *reg)
213{
214 uint32_t address = start_address;
215
216 assert((start_address + num_reg) < ID_REGISTERS_SIZE);
217
218 for (int i = 0; i < num_reg; i++)
219 {
220 reg[i] = ethosu_dev_read_reg(dev, address);
221 address += REG_OFFSET;
222 }
223
224 return ETHOSU_SUCCESS;
225}
226
227enum ethosu_error_codes ethosu_dev_set_qconfig(struct ethosu_device *dev, enum ethosu_memory_type memory_type)
228{
229 if (memory_type > ETHOSU_AXI1_OUTSTANDING_COUNTER3)
230 {
231 return ETHOSU_INVALID_PARAM;
232 }
233 ethosu_dev_write_reg(dev, NPU_REG_QCONFIG, memory_type);
234 LOG_DEBUG("QCONFIG=0x%08x\n", memory_type);
235
236 return ETHOSU_SUCCESS;
237}
238
239enum ethosu_error_codes ethosu_dev_set_regioncfg(struct ethosu_device *dev,
240 uint8_t region,
241 enum ethosu_memory_type memory_type)
242{
243 struct regioncfg_r regioncfg;
244
245 if (region > 7)
246 {
247 return ETHOSU_INVALID_PARAM;
248 }
249
250 regioncfg.word = ethosu_dev_read_reg(dev, NPU_REG_REGIONCFG);
251 regioncfg.word &= ~(0x3 << (2 * region));
252 regioncfg.word |= (memory_type & 0x3) << (2 * region);
253 ethosu_dev_write_reg(dev, NPU_REG_REGIONCFG, regioncfg.word);
254 LOG_DEBUG("REGIONCFG%u=0x%08x\n", region, regioncfg.word);
255
256 return ETHOSU_SUCCESS;
257}
258
259enum ethosu_error_codes ethosu_dev_set_axi_limit0(struct ethosu_device *dev,
260 enum ethosu_axi_limit_beats max_beats,
261 enum ethosu_axi_limit_mem_type memtype,
262 uint8_t max_reads,
263 uint8_t max_writes)
264{
265 struct axi_limit0_r axi_limit0;
266
267 axi_limit0.word = 0;
268 axi_limit0.max_beats = max_beats;
269 axi_limit0.memtype = memtype;
270 axi_limit0.max_outstanding_read_m1 = max_reads - 1;
271 axi_limit0.max_outstanding_write_m1 = max_writes - 1;
272
273 ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT0, axi_limit0.word);
274 LOG_DEBUG("AXI_LIMIT0=0x%08x\n", axi_limit0.word);
275
276 return ETHOSU_SUCCESS;
277}
278
279enum ethosu_error_codes ethosu_dev_set_axi_limit1(struct ethosu_device *dev,
280 enum ethosu_axi_limit_beats max_beats,
281 enum ethosu_axi_limit_mem_type memtype,
282 uint8_t max_reads,
283 uint8_t max_writes)
284{
285 struct axi_limit1_r axi_limit1;
286
287 axi_limit1.word = 0;
288 axi_limit1.max_beats = max_beats;
289 axi_limit1.memtype = memtype;
290 axi_limit1.max_outstanding_read_m1 = max_reads - 1;
291 axi_limit1.max_outstanding_write_m1 = max_writes - 1;
292
293 ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT1, axi_limit1.word);
294 LOG_DEBUG("AXI_LIMIT1=0x%08x\n", axi_limit1.word);
295
296 return ETHOSU_SUCCESS;
297}
298
299enum ethosu_error_codes ethosu_dev_set_axi_limit2(struct ethosu_device *dev,
300 enum ethosu_axi_limit_beats max_beats,
301 enum ethosu_axi_limit_mem_type memtype,
302 uint8_t max_reads,
303 uint8_t max_writes)
304{
305 struct axi_limit2_r axi_limit2;
306
307 axi_limit2.word = 0;
308 axi_limit2.max_beats = max_beats;
309 axi_limit2.memtype = memtype;
310 axi_limit2.max_outstanding_read_m1 = max_reads - 1;
311 axi_limit2.max_outstanding_write_m1 = max_writes - 1;
312
313 ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT2, axi_limit2.word);
314 LOG_DEBUG("AXI_LIMIT2=0x%08x\n", axi_limit2.word);
315
316 return ETHOSU_SUCCESS;
317}
318
319enum ethosu_error_codes ethosu_dev_set_axi_limit3(struct ethosu_device *dev,
320 enum ethosu_axi_limit_beats max_beats,
321 enum ethosu_axi_limit_mem_type memtype,
322 uint8_t max_reads,
323 uint8_t max_writes)
324{
325 struct axi_limit3_r axi_limit3;
326
327 axi_limit3.word = 0;
328 axi_limit3.max_beats = max_beats;
329 axi_limit3.memtype = memtype;
330 axi_limit3.max_outstanding_read_m1 = max_reads - 1;
331 axi_limit3.max_outstanding_write_m1 = max_writes - 1;
332
333 ethosu_dev_write_reg(dev, NPU_REG_AXI_LIMIT3, axi_limit3.word);
334 LOG_DEBUG("AXI_LIMIT3=0x%08x\n", axi_limit3.word);
335
336 return ETHOSU_SUCCESS;
337}
338
339enum ethosu_error_codes ethosu_dev_get_revision(struct ethosu_device *dev, uint32_t *revision)
340{
341 *revision = ethosu_dev_read_reg(dev, NPU_REG_REVISION);
342
343 return ETHOSU_SUCCESS;
344}
345
346uint32_t ethosu_dev_get_qread(struct ethosu_device *dev)
347{
348 return ethosu_dev_read_reg(dev, NPU_REG_QREAD);
349}
350
351uint32_t ethosu_dev_get_status(struct ethosu_device *dev)
352{
353 return ethosu_dev_read_reg(dev, NPU_REG_STATUS);
354}
355
356enum ethosu_error_codes ethosu_dev_get_status_mask(struct ethosu_device *dev, uint16_t *status_mask)
357{
358 struct status_r status;
359
360 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
361 *status_mask = status.word & 0xFFFF;
362
363 return ETHOSU_SUCCESS;
364}
365
366enum ethosu_error_codes ethosu_dev_get_irq_history_mask(struct ethosu_device *dev, uint16_t *irq_history_mask)
367{
368 struct status_r status;
369
370 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
371 *irq_history_mask = status.irq_history_mask;
372
373 return ETHOSU_SUCCESS;
374}
375
376enum ethosu_error_codes ethosu_dev_clear_irq_history_mask(struct ethosu_device *dev, uint16_t irq_history_clear_mask)
377{
378 struct cmd_r oldcmd;
379 struct cmd_r cmd;
380
381 oldcmd.word = ethosu_dev_read_reg(dev, NPU_REG_CMD);
382
383 cmd.word = 0;
384 cmd.clock_q_enable = oldcmd.clock_q_enable;
385 cmd.power_q_enable = oldcmd.power_q_enable;
386 cmd.clear_irq_history = irq_history_clear_mask;
387
388 ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
389 LOG_DEBUG("CMD=0x%08x\n", cmd.word);
390
391 return ETHOSU_SUCCESS;
392}
393
394enum ethosu_error_codes ethosu_dev_set_command_run(struct ethosu_device *dev)
395{
396 struct cmd_r oldcmd;
397 struct cmd_r cmd;
398
399 oldcmd.word = ethosu_dev_read_reg(dev, NPU_REG_CMD);
400
401 cmd.word = 0;
402 cmd.transition_to_running_state = 1;
403 cmd.clock_q_enable = oldcmd.clock_q_enable;
404 cmd.power_q_enable = oldcmd.power_q_enable;
405
406 ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
407 LOG_DEBUG("CMD=0x%08x\n", cmd.word);
408
409 return ETHOSU_SUCCESS;
410}
411
412enum ethosu_error_codes ethosu_dev_get_shram_data(struct ethosu_device *dev, int section, uint32_t *shram_p)
413{
414 int i = 0;
415 uint32_t address = NPU_REG_SHARED_BUFFER0;
416
417 ethosu_dev_write_reg(dev, NPU_REG_DEBUG_ADDRESS, section * BYTES_1KB);
418
419 while (address <= NPU_REG_SHARED_BUFFER255)
420 {
421 shram_p[i] = ethosu_dev_read_reg(dev, address);
422 address += REG_OFFSET;
423 i++;
424 }
425
426 return ETHOSU_SUCCESS;
427}
428
429enum ethosu_error_codes ethosu_dev_set_clock_and_power(struct ethosu_device *dev,
430 enum ethosu_clock_q_request clock_q,
431 enum ethosu_power_q_request power_q)
432{
433 struct cmd_r cmd;
434
435 cmd.word = 0;
436 cmd.clock_q_enable = clock_q;
437 cmd.power_q_enable = power_q;
438 ethosu_dev_write_reg(dev, NPU_REG_CMD, cmd.word);
439 LOG_DEBUG("CMD=0x%08x\n", cmd.word);
440
441 return ETHOSU_SUCCESS;
442}
443
444uint32_t ethosu_dev_read_reg(struct ethosu_device *dev, uint32_t address)
445{
446 assert(dev->base_address != 0);
447 assert(address % 4 == 0);
448
449 volatile uint32_t *reg = (volatile uint32_t *)(dev->base_address + address);
450 return *reg;
451}
452
453void ethosu_dev_write_reg(struct ethosu_device *dev, uint32_t address, uint32_t value)
454{
455 assert(dev->base_address != 0);
456 assert(address % 4 == 0);
457
458 volatile uint32_t *reg = (volatile uint32_t *)(dev->base_address + address);
459 *reg = value;
460}
461
462void ethosu_dev_write_reg_shadow(struct ethosu_device *dev, uint32_t address, uint32_t value, uint32_t *shadow)
463{
464 ethosu_dev_write_reg(dev, address, value);
465 *shadow = ethosu_dev_read_reg(dev, address);
466}
467
468enum ethosu_error_codes ethosu_dev_save_pmu_config(struct ethosu_device *dev)
469{
470 // Save the PMU control register
471 dev->pmcr = ethosu_dev_read_reg(dev, NPU_REG_PMCR);
472
473 // Save IRQ control
474 dev->pmint = ethosu_dev_read_reg(dev, NPU_REG_PMINTSET);
475
476 // Save the enabled events mask
477 dev->pmcnten = ethosu_dev_read_reg(dev, NPU_REG_PMCNTENSET);
478
479 // Save start and stop event
480 dev->pmccntr_cfg = ethosu_dev_read_reg(dev, NPU_REG_PMCCNTR_CFG);
481
482 // Save the event settings and counters
483 for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
484 {
485 dev->pmu_evtypr[i] = ethosu_dev_read_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t));
486 }
487
488 return ETHOSU_SUCCESS;
489}
490
491enum ethosu_error_codes ethosu_dev_restore_pmu_config(struct ethosu_device *dev)
492{
493 // Restore PMU control register
494 ethosu_dev_write_reg(dev, NPU_REG_PMCR, dev->pmcr);
495
496 // Restore IRQ control
497 ethosu_dev_write_reg(dev, NPU_REG_PMINTSET, dev->pmint);
498
499 // Restore enabled event mask
500 ethosu_dev_write_reg(dev, NPU_REG_PMCNTENSET, dev->pmcnten);
501
502 // Restore start and stop event
503 ethosu_dev_write_reg(dev, NPU_REG_PMCCNTR_CFG, dev->pmccntr_cfg);
504
505 // Save the event settings and counters
506 for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
507 {
508 ethosu_dev_write_reg(dev, NPU_REG_PMEVTYPER0 + i * sizeof(uint32_t), dev->pmu_evtypr[i]);
509 }
510
511 return ETHOSU_SUCCESS;
512}
513
514enum ethosu_error_codes ethosu_dev_save_pmu_counters(struct ethosu_device *dev)
515{
516 // Save the cycle counter
517 dev->pmccntr[0] = ethosu_dev_read_reg(dev, NPU_REG_PMCCNTR_LO);
518 dev->pmccntr[1] = ethosu_dev_read_reg(dev, NPU_REG_PMCCNTR_HI);
519
520 // Save the event settings and counters
521 for (uint32_t i = 0; i < ETHOSU_PMU_NCOUNTERS; i++)
522 {
523 dev->pmu_evcntr[i] = ethosu_dev_read_reg(dev, NPU_REG_PMEVCNTR0 + i * sizeof(uint32_t));
524 }
525
526 return ETHOSU_SUCCESS;
527}
528
529bool ethosu_dev_prot_has_changed(struct ethosu_device *dev)
530{
531 if (dev->proto != ethosu_dev_read_reg(dev, NPU_REG_PROT))
532 {
533 return true;
534 }
535
536 return false;
537}
538
539bool ethosu_dev_status_has_error(struct ethosu_device *dev)
540{
541 bool status_error = false;
542 struct status_r status;
543
544 status.word = ethosu_dev_read_reg(dev, NPU_REG_STATUS);
545 status_error = ((1 == status.bus_status) || (1 == status.cmd_parse_error) || (1 == status.wd_fault) ||
546 (1 == status.ecc_fault));
547
548 return status_error;
549}