1 // Copyright 2021 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "esp_crypto_shared_gdma.h"
16
17 #include "freertos/FreeRTOS.h"
18 #include "freertos/task.h"
19
20 #include "hal/gdma_ll.h"
21 #include "soc/soc_caps.h"
22 #include "esp_log.h"
23 #include "esp_err.h"
24 #include "esp_crypto_lock.h"
25
26 #define NEW_CHANNEL_TIMEOUT_MS 1000
27 #define NEW_CHANNEL_DELAY_MS 100
28
29 static const char *TAG = "crypto_shared_gdma";
30
31 static gdma_channel_handle_t rx_channel;
32 static gdma_channel_handle_t tx_channel;
33
34 /* Allocate a new GDMA channel, will keep trying until NEW_CHANNEL_TIMEOUT_MS */
crypto_shared_gdma_new_channel(gdma_channel_alloc_config_t * channel_config,gdma_channel_handle_t * channel)35 static inline esp_err_t crypto_shared_gdma_new_channel(gdma_channel_alloc_config_t *channel_config, gdma_channel_handle_t *channel)
36 {
37 esp_err_t ret;
38 int time_waited_ms = 0;
39
40 while(1) {
41 ret = gdma_new_channel(channel_config, channel);
42
43 if (ret == ESP_OK) {
44 break;
45 } else if (time_waited_ms >= NEW_CHANNEL_TIMEOUT_MS) {
46 *channel = NULL;
47 break;
48 }
49
50 time_waited_ms += NEW_CHANNEL_DELAY_MS;
51 vTaskDelay(NEW_CHANNEL_DELAY_MS / portTICK_PERIOD_MS);
52 }
53 return ret;
54 }
55
56
57 #if SOC_GDMA_SUPPORT_EXTMEM
58 /* Initialize external memory specific DMA configs */
esp_crypto_shared_dma_init_extmem(void)59 static void esp_crypto_shared_dma_init_extmem(void)
60 {
61 int tx_ch_id = 0;
62 int rx_ch_id = 0;
63
64 gdma_get_channel_id(tx_channel, &tx_ch_id);
65 gdma_get_channel_id(rx_channel, &rx_ch_id);
66
67 /* An L2 FIFO bigger than 40 bytes is need when accessing external ram */
68 gdma_ll_tx_extend_fifo_size_to(&GDMA, tx_ch_id, 40);
69 gdma_ll_rx_extend_l2_fifo_size_to(&GDMA, rx_ch_id, 40);
70 gdma_ll_tx_set_block_size_psram(&GDMA, tx_ch_id, GDMA_OUT_EXT_MEM_BK_SIZE_16B);
71 gdma_ll_rx_set_block_size_psram(&GDMA, rx_ch_id, GDMA_OUT_EXT_MEM_BK_SIZE_16B);
72 }
73 #endif //SOC_GDMA_SUPPORT_EXTMEM
74
75 /* Initialize GDMA module and channels */
crypto_shared_gdma_init(void)76 static esp_err_t crypto_shared_gdma_init(void)
77 {
78 esp_err_t ret;
79
80 gdma_channel_alloc_config_t channel_config_tx = {
81 .direction = GDMA_CHANNEL_DIRECTION_TX,
82 };
83
84 gdma_channel_alloc_config_t channel_config_rx = {
85 .direction = GDMA_CHANNEL_DIRECTION_RX,
86 };
87
88 ret = crypto_shared_gdma_new_channel(&channel_config_tx, &tx_channel);
89 if (ret != ESP_OK) {
90 goto err;
91 }
92
93 ret = crypto_shared_gdma_new_channel(&channel_config_rx, &rx_channel);
94 if (ret != ESP_OK) {
95 gdma_del_channel(tx_channel); // Clean up already allocated TX channel
96 goto err;
97 }
98
99 #if SOC_GDMA_SUPPORT_EXTMEM
100 esp_crypto_shared_dma_init_extmem();
101 #endif //SOC_GDMA_SUPPORT_EXTMEM
102
103 gdma_connect(rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
104 gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
105
106 return ESP_OK;
107
108 err:
109 ESP_LOGE(TAG, "Failed to acquire DMA channel, Err=0x%X", ret);
110 tx_channel = NULL;
111 rx_channel = NULL;
112
113 return ret;
114 }
115
116
esp_crypto_shared_gdma_start(const lldesc_t * input,const lldesc_t * output,gdma_trigger_peripheral_t peripheral)117 esp_err_t esp_crypto_shared_gdma_start(const lldesc_t *input, const lldesc_t *output, gdma_trigger_peripheral_t peripheral)
118 {
119 int rx_ch_id = 0;
120 esp_err_t ret = ESP_OK;
121
122 if (tx_channel == NULL) {
123 /* Allocate a pair of RX and TX for crypto, should only happen the first time we use the GMDA
124 or if user called esp_crypto_shared_gdma_release */
125 ret = crypto_shared_gdma_init();
126 }
127
128 if (ret != ESP_OK) {
129 return ret;
130 }
131
132 /* Tx channel is shared between AES and SHA, need to connect to peripheral every time */
133 gdma_disconnect(tx_channel);
134
135 if (peripheral == GDMA_TRIG_PERIPH_SHA) {
136 gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0));
137 } else if (peripheral == GDMA_TRIG_PERIPH_AES) {
138 gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0));
139 } else {
140 return ESP_ERR_INVALID_ARG;
141 }
142
143 /* tx channel is reset by gdma_connect(), also reset rx to ensure a known state */
144 gdma_get_channel_id(tx_channel, &rx_ch_id);
145 gdma_ll_rx_reset_channel(&GDMA, rx_ch_id);
146
147 gdma_start(tx_channel, (intptr_t)input);
148 gdma_start(rx_channel, (intptr_t)output);
149
150 return ESP_OK;
151 }
152
esp_crypto_shared_gdma_free()153 void esp_crypto_shared_gdma_free()
154 {
155 esp_crypto_sha_aes_lock_acquire();
156
157 if (rx_channel != NULL) {
158 gdma_disconnect(rx_channel);
159 gdma_del_channel(rx_channel);
160 rx_channel = NULL;
161 }
162
163 if (tx_channel != NULL) {
164 gdma_disconnect(tx_channel);
165 gdma_del_channel(tx_channel);
166 tx_channel = NULL;
167 }
168
169 esp_crypto_sha_aes_lock_release();
170 }
171