1 /*
2  * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stdint.h>
9 #include "bootutil/bootutil_log.h"
10 #include "boot_dma.h"
11 #include "tfm_hal_device_header.h"
12 #include "tfm_plat_defs.h"
13 #include "dma350_lib.h"
14 #include "device_definition.h"
15 
16 #define BOOT_DMA0_COMBINED_S_SIGNAL                             (24)
17 #define BOOT_DMA_NUM_CHANNELS                                   (4)
18 
19 static struct dma350_ch_dev_t *const dma350_channel_list[BOOT_DMA_NUM_CHANNELS] = {
20     &DMA350_DMA0_CH0_DEV_S,
21     &DMA350_DMA0_CH1_DEV_S,
22     &DMA350_DMA0_CH2_DEV_S,
23     &DMA350_DMA0_CH3_DEV_S
24 };
25 
26 /* DMA350 checker layer has to know the TCM remaps */
27 /* Subordinate TCM Interface provides system access only to TCM internal to each
28  * CPU. The memory map presented on the interface for TCM access are defined by
29  * TRM. Below address remaps by adding offset provides access to respective
30  * CPU instruction and data TCM.
31  */
32 
33 /* TCM memories addresses from perspective of cpu0
34  * 0x0000_0000 .. 0x00ff_ffff    NS ITCM
35  * 0x1000_0000 .. 0x10ff_ffff    S ITCM
36  * 0x2000_0000 .. 0x20ff_ffff    NS DTCM
37  * 0x3000_0000 .. 0x30ff_ffff    S DTCM
38 */
39 
40 const struct dma350_remap_range_t dma350_address_remap_list[] = {
41     /* Non-secure CPU ITCM */
42     {.begin = 0x00000000, .end = 0x00FFFFFF, .offset = 0x0A000000},
43     /* Secure CPU ITCM */
44     {.begin = 0x10000000, .end = 0x10FFFFFF, .offset = 0x0A000000},
45     /* Non-secure CPU DTCM */
46     {.begin = 0x20000000, .end = 0x20FFFFFF, .offset = 0x04000000},
47     /* Secure CPU DTCM */
48     {.begin = 0x30000000, .end = 0x30FFFFFF, .offset = 0x04000000}
49 };
50 
51 const struct dma350_remap_list_t dma350_address_remap = {
52     .size = sizeof(dma350_address_remap_list)/
53             sizeof(dma350_address_remap_list[0]),
54     .map = dma350_address_remap_list
55 };
56 
57 /*------------------- DMA configuration functions -------------------------*/
boot_dma_init_cfg(void)58 enum tfm_plat_err_t boot_dma_init_cfg(void)
59 {
60     enum dma350_error_t dma_err;
61     enum dma350_ch_error_t ch_err;
62     struct dma350_ch_dev_t *dma_ch_ptr;
63     uint32_t i;
64 
65     dma_err = dma350_init(&DMA350_DMA0_DEV_S);
66     if (dma_err != DMA350_ERR_NONE) {
67         BOOT_LOG_ERR("DMA350_DMA0_DEV_S init failed!");
68         return TFM_PLAT_ERR_SYSTEM_ERR;
69     }
70 
71     for (i = 0; i < BOOT_DMA_NUM_CHANNELS; i++) {
72         dma_ch_ptr = dma350_channel_list[i];
73 
74         ch_err = dma350_ch_init(dma_ch_ptr);
75         if (ch_err != DMA350_CH_ERR_NONE) {
76             BOOT_LOG_ERR("DMA350_DMA0_CH%u_DEV_S init failed!", i);
77             return TFM_PLAT_ERR_SYSTEM_ERR;
78         }
79 
80         dma_err = dma350_set_ch_privileged(&DMA350_DMA0_DEV_S, i);
81         if (dma_err != DMA350_ERR_NONE) {
82             BOOT_LOG_ERR("Failed to set DMA350_DM0 channel:%u privileged!",
83                          i);
84             return TFM_PLAT_ERR_SYSTEM_ERR;
85         }
86 
87         dma_err = dma350_set_ch_secure(&DMA350_DMA0_DEV_S, i);
88         if (dma_err != DMA350_ERR_NONE) {
89             BOOT_LOG_ERR("Failed to set DMA350_DM0 channel:%u secure!",
90                          i);
91             return TFM_PLAT_ERR_SYSTEM_ERR;
92         }
93     }
94 
95     /* Use combined secure interrupt because there are no channel IRQs */
96     DMA350_DMA0_DEV_S.cfg->dma_sec_ctrl->SEC_CTRL |= 0x1UL;
97     DMA350_DMA0_DEV_S.cfg->dma_nsec_ctrl->NSEC_CTRL |= 0x1UL;
98 
99     return TFM_PLAT_ERR_SUCCESS;
100 }
101 
boot_dma_memcpy(uint32_t src_addr,uint32_t dest_addr,uint32_t size,uint32_t ch_idx)102 int32_t boot_dma_memcpy(uint32_t src_addr,
103                         uint32_t dest_addr,
104                         uint32_t size,
105                         uint32_t ch_idx)
106 {
107     struct dma350_ch_dev_t *dma_ch_ptr;
108     enum dma350_lib_error_t dma_config_ret_val =
109                                              DMA350_LIB_ERR_INVALID_CONFIG_TYPE;
110 
111     if (ch_idx >= BOOT_DMA_NUM_CHANNELS) {
112         BOOT_LOG_ERR("[DMA350 BL2] Input dma channel: %u is invalid \r\n",
113                      ch_idx);
114         return -1;
115     }
116 
117     dma_ch_ptr = dma350_channel_list[ch_idx];
118     dma_config_ret_val = dma350_memcpy(dma_ch_ptr,
119                                        (void *)src_addr,
120                                        (void *)dest_addr,
121                                        size,
122                                        DMA350_LIB_EXEC_BLOCKING);
123 
124     if (dma_config_ret_val != 0) {
125         BOOT_LOG_ERR("[DMA350 BL2] dma350_memcpy return value: 0x%x",
126                      dma_config_ret_val);
127         BOOT_LOG_ERR("[DMA350 BL2] Fail to copy %u bytes from 0x%x to 0x%x",
128                      size, src_addr, dest_addr);
129         return -1;
130     }
131 
132     return 0;
133 }
134