Software APIs
dif_mbx.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
10
11#include "mbx_regs.h" // Generated.
12
13dif_result_t dif_mbx_range_set(const dif_mbx_t *mbx,
15 if (mbx == NULL) {
16 return kDifBadArg;
17 }
18 // Note: the limit addresses are _inclusive_, specifying the start address of
19 // the final valid DWORD.
20 if (config.imbx_base_addr > config.imbx_limit_addr) {
21 return kDifBadArg;
22 }
23 if (config.ombx_base_addr > config.ombx_limit_addr) {
24 return kDifBadArg;
25 }
26 // Check that the inbound mailbox and outbound mailbox memory ranges do not
27 // collide with each other.
28 if ((config.imbx_base_addr <= config.ombx_limit_addr) &&
29 (config.ombx_base_addr <= config.imbx_limit_addr)) {
30 return kDifBadArg;
31 }
32
33 mmio_region_write32(mbx->base_addr, MBX_INBOUND_BASE_ADDRESS_REG_OFFSET,
34 config.imbx_base_addr);
35 mmio_region_write32(mbx->base_addr, MBX_INBOUND_LIMIT_ADDRESS_REG_OFFSET,
36 config.imbx_limit_addr);
37 mmio_region_write32(mbx->base_addr, MBX_OUTBOUND_BASE_ADDRESS_REG_OFFSET,
38 config.ombx_base_addr);
39 mmio_region_write32(mbx->base_addr, MBX_OUTBOUND_LIMIT_ADDRESS_REG_OFFSET,
40 config.ombx_limit_addr);
41 // Indicate the range configuration to be valid.
42 mmio_region_write32(mbx->base_addr, MBX_ADDRESS_RANGE_VALID_REG_OFFSET, 1);
43
44 return kDifOk;
45}
46
47dif_result_t dif_mbx_range_get(const dif_mbx_t *mbx,
48 dif_mbx_range_config_t *config) {
49 if (mbx == NULL || config == NULL) {
50 return kDifBadArg;
51 }
52
53 config->imbx_base_addr =
54 mmio_region_read32(mbx->base_addr, MBX_INBOUND_BASE_ADDRESS_REG_OFFSET);
55 config->imbx_limit_addr =
56 mmio_region_read32(mbx->base_addr, MBX_INBOUND_LIMIT_ADDRESS_REG_OFFSET);
57 config->ombx_base_addr =
58 mmio_region_read32(mbx->base_addr, MBX_OUTBOUND_BASE_ADDRESS_REG_OFFSET);
59 config->ombx_limit_addr =
60 mmio_region_read32(mbx->base_addr, MBX_OUTBOUND_LIMIT_ADDRESS_REG_OFFSET);
61 return kDifOk;
62}
63
64dif_result_t dif_mbx_is_busy(const dif_mbx_t *mbx, bool *is_busy) {
65 if (mbx == NULL || is_busy == NULL) {
66 return kDifBadArg;
67 }
68
69 *is_busy = (bitfield_bit32_read(
70 mmio_region_read32(mbx->base_addr, MBX_STATUS_REG_OFFSET),
71 MBX_STATUS_BUSY_BIT) == 1);
72 return kDifOk;
73}
74
75dif_result_t dif_mbx_ipi_configuration_get(const dif_mbx_t *mbx,
76 uint32_t *doe_intr_addr,
77 uint32_t *doe_intr_data) {
78 if (mbx == NULL || doe_intr_addr == NULL || doe_intr_data == NULL) {
79 return kDifBadArg;
80 }
81
82 *doe_intr_addr =
83 mmio_region_read32(mbx->base_addr, MBX_DOE_INTR_MSG_ADDR_REG_OFFSET);
84 *doe_intr_data =
85 mmio_region_read32(mbx->base_addr, MBX_DOE_INTR_MSG_DATA_REG_OFFSET);
86
87 return kDifOk;
88}
89
90dif_result_t dif_mbx_process_request(const dif_mbx_t *mbx,
91 dif_mbx_transaction_t *request) {
92 if (mbx == NULL || request == NULL || request->data_dwords == NULL) {
93 return kDifBadArg;
94 }
95
96 uint32_t curr_ptr =
97 mmio_region_read32(mbx->base_addr, MBX_INBOUND_BASE_ADDRESS_REG_OFFSET);
98 uint32_t imbx_wr_ptr =
99 mmio_region_read32(mbx->base_addr, MBX_INBOUND_WRITE_PTR_REG_OFFSET);
100
101 // Read from base until the write pointer or we hit the limit of maximum
102 // dwords.
103 uint32_t read_dwords = 0;
104 while (curr_ptr < imbx_wr_ptr && read_dwords < request->nr_dwords) {
105 request->data_dwords[read_dwords++] = abs_mmio_read32(curr_ptr);
106 curr_ptr += sizeof(uint32_t);
107 }
108
109 // Pass back the actual number of read words
110 request->nr_dwords = read_dwords;
111
112 // If the read pointer didn't hit the write pointer, it means we hit the limit
113 // of maximum dwords supported by the destination
114 if (curr_ptr < imbx_wr_ptr) {
115 return kDifOutOfRange;
116 }
117
118 return kDifOk;
119}
120
121dif_result_t dif_mbx_generate_response(const dif_mbx_t *mbx,
122 const dif_mbx_transaction_t response) {
123 uint32_t curr_ptr;
124
125 if (mbx == NULL || response.data_dwords == NULL ||
126 response.nr_dwords > DOE_MAILBOX_MAX_OBJECT_SIZE) {
127 return kDifBadArg;
128 }
129
130 curr_ptr =
131 mmio_region_read32(mbx->base_addr, MBX_OUTBOUND_READ_PTR_REG_OFFSET);
132 for (uint32_t i = 0; i < response.nr_dwords; ++i) {
133 abs_mmio_write32(curr_ptr, response.data_dwords[i]);
134 curr_ptr += sizeof(uint32_t);
135 }
136
137 mmio_region_write32(mbx->base_addr, MBX_OUTBOUND_OBJECT_SIZE_REG_OFFSET,
138 response.nr_dwords);
139
140 return kDifOk;
141}