Software APIs
dif_dma.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
12 
13 static_assert(kDifDmaOpentitanInternalBus ==
14  DMA_ADDR_SPACE_ID_DST_ASID_VALUE_OT_ADDR,
15  "Address Space ID mismatches with value defined in HW");
16 static_assert(kDifDmaSoCControlRegisterBus ==
17  DMA_ADDR_SPACE_ID_DST_ASID_VALUE_SOC_ADDR,
18  "Address Space ID mismatches with value defined in HW");
19 static_assert(kDifDmaSoCSystemBus == DMA_ADDR_SPACE_ID_DST_ASID_VALUE_SYS_ADDR_,
20  "Address Space ID mismatches with value defined in HW");
21 
23  dif_dma_transaction_t transaction) {
24  if (dma == NULL) {
25  return kDifBadArg;
26  }
27 
28  mmio_region_write32(dma->base_addr, DMA_SRC_ADDR_LO_REG_OFFSET,
29  transaction.source.address & UINT32_MAX);
30  mmio_region_write32(dma->base_addr, DMA_SRC_ADDR_HI_REG_OFFSET,
31  transaction.source.address >> (sizeof(uint32_t) * 8));
32 
33  mmio_region_write32(dma->base_addr, DMA_DST_ADDR_LO_REG_OFFSET,
34  transaction.destination.address & UINT32_MAX);
35  mmio_region_write32(
36  dma->base_addr, DMA_DST_ADDR_HI_REG_OFFSET,
37  transaction.destination.address >> (sizeof(uint32_t) * 8));
38 
39  uint32_t reg = 0;
40  reg = bitfield_field32_write(reg, DMA_ADDR_SPACE_ID_SRC_ASID_FIELD,
41  transaction.source.asid);
42  reg = bitfield_field32_write(reg, DMA_ADDR_SPACE_ID_DST_ASID_FIELD,
43  transaction.destination.asid);
44  mmio_region_write32(dma->base_addr, DMA_ADDR_SPACE_ID_REG_OFFSET, reg);
45 
46  mmio_region_write32(dma->base_addr, DMA_CHUNK_DATA_SIZE_REG_OFFSET,
47  transaction.chunk_size);
48  mmio_region_write32(dma->base_addr, DMA_TOTAL_DATA_SIZE_REG_OFFSET,
49  transaction.total_size);
50  mmio_region_write32(dma->base_addr, DMA_TRANSFER_WIDTH_REG_OFFSET,
51  transaction.width);
52 
53  return kDifOk;
54 }
55 
57  dif_dma_handshake_t handshake) {
58  if (dma == NULL) {
59  return kDifBadArg;
60  }
61 
62  uint32_t reg = mmio_region_read32(dma->base_addr, DMA_CONTROL_REG_OFFSET);
63  reg = bitfield_bit32_write(reg, DMA_CONTROL_HARDWARE_HANDSHAKE_ENABLE_BIT,
64  true);
65  reg = bitfield_bit32_write(reg, DMA_CONTROL_FIFO_AUTO_INCREMENT_ENABLE_BIT,
66  handshake.fifo_auto_increment);
68  reg, DMA_CONTROL_MEMORY_BUFFER_AUTO_INCREMENT_ENABLE_BIT,
69  handshake.memory_auto_increment);
70  reg = bitfield_bit32_write(reg, DMA_CONTROL_DATA_DIRECTION_BIT,
71  handshake.direction_from_mem_to_fifo);
72  mmio_region_write32(dma->base_addr, DMA_CONTROL_REG_OFFSET, reg);
73  return kDifOk;
74 }
75 
77  if (dma == NULL) {
78  return kDifBadArg;
79  }
80 
81  uint32_t reg = mmio_region_read32(dma->base_addr, DMA_CONTROL_REG_OFFSET);
82  reg = bitfield_bit32_write(reg, DMA_CONTROL_HARDWARE_HANDSHAKE_ENABLE_BIT,
83  false);
84  mmio_region_write32(dma->base_addr, DMA_CONTROL_REG_OFFSET, reg);
85  return kDifOk;
86 }
87 
89  dif_dma_transaction_opcode_t opcode) {
90  if (dma == NULL) {
91  return kDifBadArg;
92  }
93 
94  uint32_t reg = mmio_region_read32(dma->base_addr, DMA_CONTROL_REG_OFFSET);
95  reg = bitfield_field32_write(reg, DMA_CONTROL_OPCODE_FIELD, opcode);
96  reg = bitfield_bit32_write(reg, DMA_CONTROL_GO_BIT, 1);
97  reg = bitfield_bit32_write(reg, DMA_CONTROL_INITIAL_TRANSFER_BIT, 1);
98  mmio_region_write32(dma->base_addr, DMA_CONTROL_REG_OFFSET, reg);
99  return kDifOk;
100 }
101 
103  if (dma == NULL) {
104  return kDifBadArg;
105  }
106 
107  uint32_t reg = mmio_region_read32(dma->base_addr, DMA_CONTROL_REG_OFFSET);
108  reg = bitfield_bit32_write(reg, DMA_CONTROL_ABORT_BIT, 1);
109  mmio_region_write32(dma->base_addr, DMA_CONTROL_REG_OFFSET, reg);
110  return kDifOk;
111 }
112 
113 dif_result_t dif_dma_memory_range_set(const dif_dma_t *dma, uint32_t address,
114  size_t size) {
115  if (dma == NULL || size == 0) {
116  return kDifBadArg;
117  }
118 
119  mmio_region_write32(dma->base_addr, DMA_ENABLED_MEMORY_RANGE_BASE_REG_OFFSET,
120  address);
121  // The limit address is inclusive so we subtract one.
122  uint32_t end_addr = address + size - 1;
123  mmio_region_write32(dma->base_addr, DMA_ENABLED_MEMORY_RANGE_LIMIT_REG_OFFSET,
124  end_addr);
125  // Indicate the range to be valid
126  mmio_region_write32(dma->base_addr, DMA_RANGE_VALID_REG_OFFSET, 1);
127 
128  return kDifOk;
129 }
130 
131 dif_result_t dif_dma_memory_range_get(const dif_dma_t *dma, uint32_t *address,
132  size_t *size) {
133  if (dma == NULL || size == NULL || address == NULL) {
134  return kDifBadArg;
135  }
136 
137  *address = mmio_region_read32(dma->base_addr,
138  DMA_ENABLED_MEMORY_RANGE_BASE_REG_OFFSET);
139 
140  // The limit address is inclusive so we add one.
141  *size = mmio_region_read32(dma->base_addr,
142  DMA_ENABLED_MEMORY_RANGE_LIMIT_REG_OFFSET) -
143  *address + 1;
144 
145  return kDifOk;
146 }
147 
149  if (dma == NULL) {
150  return kDifBadArg;
151  }
152 
153  mmio_region_write32(dma->base_addr, DMA_RANGE_REGWEN_REG_OFFSET,
154  kMultiBitBool4False);
155  return kDifOk;
156 }
157 
159  bool *is_locked) {
160  if (dma == NULL || is_locked == NULL) {
161  return kDifBadArg;
162  }
163 
164  *is_locked = kMultiBitBool4False ==
165  mmio_region_read32(dma->base_addr, DMA_RANGE_REGWEN_REG_OFFSET);
166  return kDifOk;
167 }
168 
170  bool *is_valid) {
171  if (dma == NULL || is_valid == NULL) {
172  return kDifBadArg;
173  }
174 
175  *is_valid = mmio_region_read32(dma->base_addr, DMA_RANGE_VALID_REG_OFFSET);
176  return kDifOk;
177 }
178 
181  if (dma == NULL || status == NULL) {
182  return kDifBadArg;
183  }
184  *status = mmio_region_read32(dma->base_addr, DMA_STATUS_REG_OFFSET);
185 
186  return kDifOk;
187 }
188 
191  if (dma == NULL) {
192  return kDifBadArg;
193  }
194  mmio_region_write32(dma->base_addr, DMA_STATUS_REG_OFFSET, status);
195 
196  return kDifOk;
197 }
198 
200  return dif_dma_status_write(dma, kDifDmaStatusDone | kDifDmaStatusAborted |
201  kDifDmaStatusError | kDifDmaStatusError);
202 }
203 
205  dif_dma_status_code_t flag) {
206  while (true) {
209 
210  if (status & flag) {
211  break;
212  }
213  if (status & kDifDmaStatusError) {
214  return kDifError;
215  }
216  }
217  return kDifOk;
218 }
219 
221  dif_dma_error_code_t *error) {
222  if (dma == NULL || error == NULL) {
223  return kDifBadArg;
224  }
225  *error = mmio_region_read32(dma->base_addr, DMA_ERROR_CODE_REG_OFFSET);
226 
227  return kDifOk;
228 }
229 
230 dif_result_t dif_dma_get_digest_length(dif_dma_transaction_opcode_t opcode,
231  uint32_t *digest_len) {
232  if (digest_len == NULL) {
233  return kDifBadArg;
234  }
235  switch (opcode) {
236  case kDifDmaSha256Opcode:
237  *digest_len = 8;
238  break;
239  case kDifDmaSha384Opcode:
240  *digest_len = 12;
241  break;
242  case kDifDmaSha512Opcode:
243  *digest_len = 16;
244  break;
245  default:
246  return kDifBadArg;
247  break;
248  }
249  return kDifOk;
250 }
251 
253  dif_dma_transaction_opcode_t opcode,
254  uint32_t digest[]) {
255  if (dma == NULL || digest == NULL) {
256  return kDifBadArg;
257  }
258 
259  uint32_t digest_len;
260  DIF_RETURN_IF_ERROR(dif_dma_get_digest_length(opcode, &digest_len));
261 
262  for (int i = 0; i < digest_len; ++i) {
263  ptrdiff_t offset = DMA_SHA2_DIGEST_0_REG_OFFSET +
264  (ptrdiff_t)i * (ptrdiff_t)sizeof(uint32_t);
265 
266  digest[i] = mmio_region_read32(dma->base_addr, offset);
267  }
268  return kDifOk;
269 }
270 
272  uint32_t enable_state) {
273  if (dma == NULL) {
274  return kDifBadArg;
275  }
276  mmio_region_write32(dma->base_addr, DMA_HANDSHAKE_INTR_ENABLE_REG_OFFSET,
277  enable_state);
278  return kDifOk;
279 }
280 
282  uint32_t clear_state) {
283  if (dma == NULL) {
284  return kDifBadArg;
285  }
286  mmio_region_write32(dma->base_addr, DMA_CLEAR_INTR_SRC_REG_OFFSET,
287  clear_state);
288 
289  return kDifOk;
290 }
291 
293  uint32_t clear_irq_bus) {
294  if (dma == NULL) {
295  return kDifBadArg;
296  }
297  mmio_region_write32(dma->base_addr, DMA_CLEAR_INTR_BUS_REG_OFFSET,
298  clear_irq_bus);
299 
300  return kDifOk;
301 }
302 
304  uint32_t intr_src_addr) {
305  if (dma == NULL) {
306  return kDifBadArg;
307  }
308  mmio_region_write32(dma->base_addr,
309  DMA_INTR_SRC_ADDR_0_REG_OFFSET + (ptrdiff_t)idx,
310  intr_src_addr);
311  return kDifOk;
312 }
313 
315  dif_dma_intr_idx_t idx,
316  uint32_t intr_src_value) {
317  if (dma == NULL) {
318  return kDifBadArg;
319  }
320  mmio_region_write32(dma->base_addr,
321  DMA_INTR_SRC_WR_VAL_0_REG_OFFSET + (ptrdiff_t)idx,
322  intr_src_value);
323  return kDifOk;
324 }