1 /*
2 * Copyright 2024 Microchip Technology Inc. and its subsidiaries.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stddef.h>
7 #include <stdint.h>
8
9 #include <device_mec5.h>
10 #include "mec_defs.h"
11 #include "mec_bdp_api.h"
12 #include "mec_ecia_api.h"
13 #include "mec_pcr_api.h"
14 #include "mec_retval.h"
15
16 #define MEC_BDP_GIRQ 15
17 #define MEC_BDP_GIRQ_POS 22
18 #define MEC_BDP_AGGR_NVIC 7
19 #define MEC_BDP_NVIC 62
20 #define MEC_BDP_ECIA_INFO \
21 MEC5_ECIA_INFO(MEC_BDP_GIRQ, MEC_BDP_GIRQ_POS, MEC_BDP_AGGR_NVIC, MEC_BDP_NVIC)
22
23 #define MEC_BDP_INTR_EN_THRES_POS 0
24
25 /* BDP Configuration register */
26 #define MEC_BDP_CFG_REG_FIFO_FIFO_FLUSH_POS 0
27 #define MEC_BDP_CFG_REG_FIFO_SNAP_CLR_POS 1
28 #define MEC_BDP_CFG_REG_FIFO_THRH_POS 8
29 #define MEC_BDP_CFG_REG_FIFO_THRH_MSK 0x700u
30 #define MEC_BDP_CFG_REG_SRESET_POS 31
31
32 /* BDP Interrupt enable register */
33 #define MEC_BDP_IEN_REG_THRH_POS 0
34
35 /* BDP Activate and Alias Activate registers */
36 #define MEC_BDP_ACTV_REG_EN_POS 0
37
38 /* ---- Public API ---- */
39
40 /* Initialize BDP */
mec_hal_bdp_init(struct mec_bdp_regs * regs,uint32_t cfg_flags)41 int mec_hal_bdp_init(struct mec_bdp_regs *regs, uint32_t cfg_flags)
42 {
43 uint32_t temp = 0;
44
45 if (!regs) {
46 return MEC_RET_ERR_INVAL;
47 }
48
49 mec_hal_girq_ctrl(MEC_BDP_ECIA_INFO, 0); /* disable */
50 mec_hal_pcr_clr_blk_slp_en(MEC_PCR_P80BD0); /* clear sleep enable */
51
52 regs->ACTV80 = 0;
53 regs->ACTV80A = 0;
54
55 /* soft-reset */
56 regs->CONFIG = MEC_BIT(MEC_BDP_CFG_REG_SRESET_POS);
57
58 /* threshold level(defaults to 1) */
59 temp = (cfg_flags & MEC5_BDP_CFG_FIFO_THRES_MSK) >> MEC5_BDP_CFG_FIFO_THRES_POS;
60 regs->CONFIG = (regs->CONFIG & (uint32_t)~(MEC_BDP_CFG_REG_FIFO_THRH_MSK))
61 | ((temp << MEC_BDP_CFG_REG_FIFO_THRH_POS) & MEC_BDP_CFG_REG_FIFO_THRH_MSK);
62
63 /* set byte lane the alias byte is mapped to */
64 if (cfg_flags & MEC_BIT(MEC5_BDP_CFG_ALIAS_EN_POS)) {
65 regs->BL80A =
66 ((cfg_flags & MEC5_BDP_CFG_ALIAS_BYTE_LANE_MSK) >> MEC5_BDP_CFG_ALIAS_BYTE_LANE_POS);
67 }
68
69 /* threshold interrupt? */
70 if (cfg_flags & MEC_BIT(MEC5_BDP_CFG_THRH_IEN_POS)) {
71 regs->IEN |= MEC_BIT(MEC_BDP_IEN_REG_THRH_POS);
72 }
73
74 /* activate */
75 if (cfg_flags & MEC_BIT(MEC5_BDP_CFG_ALIAS_EN_POS)) {
76 if (cfg_flags & MEC_BIT(MEC5_BDP_CFG_ALIAS_ACTV_POS)) {
77 regs->ACTV80A |= MEC_BIT(MEC_BDP_ACTV_REG_EN_POS);
78 }
79 }
80
81 if (cfg_flags & MEC_BIT(MEC5_BDP_CFG_ACTV_POS)) {
82 regs->ACTV80 |= MEC_BIT(MEC_BDP_ACTV_REG_EN_POS);
83 }
84
85 return MEC_RET_OK;
86 }
87
mec_hal_bdp_activate(struct mec_bdp_regs * regs,uint8_t enable,uint8_t is_alias)88 int mec_hal_bdp_activate(struct mec_bdp_regs *regs, uint8_t enable, uint8_t is_alias)
89 {
90 if (!regs) {
91 return MEC_RET_ERR_INVAL;
92 }
93
94 if (!is_alias) {
95 if (enable) {
96 regs->ACTV80 |= MEC_BIT(MEC_BDP_ACTV_REG_EN_POS);
97 } else {
98 regs->ACTV80 &= (uint8_t)~MEC_BIT(MEC_BDP_ACTV_REG_EN_POS);
99 }
100 } else {
101 if (enable) {
102 regs->ACTV80A |= MEC_BIT(MEC_BDP_ACTV_REG_EN_POS);
103 } else {
104 regs->ACTV80A &= (uint8_t)~MEC_BIT(MEC_BDP_ACTV_REG_EN_POS);
105 }
106 }
107
108 return MEC_RET_OK;
109 }
110
mec_hal_bdp_girq_ctrl(struct mec_bdp_regs * regs,uint8_t enable)111 int mec_hal_bdp_girq_ctrl(struct mec_bdp_regs *regs, uint8_t enable)
112 {
113 if (!regs) {
114 return MEC_RET_ERR_INVAL;
115 }
116
117 mec_hal_girq_ctrl(MEC_BDP_ECIA_INFO, enable);
118
119 return MEC_RET_OK;
120 }
121
mec_hal_bdp_girq_status_clr(struct mec_bdp_regs * regs)122 int mec_hal_bdp_girq_status_clr(struct mec_bdp_regs *regs)
123 {
124 if (!regs) {
125 return MEC_RET_ERR_INVAL;
126 }
127
128 mec_hal_girq_clr_src(MEC_BDP_ECIA_INFO);
129
130 return MEC_RET_OK;
131 }
132
mec_hal_bdp_fifo_thresh_set(struct mec_bdp_regs * regs,uint32_t cfg_thrh)133 int mec_hal_bdp_fifo_thresh_set(struct mec_bdp_regs *regs, uint32_t cfg_thrh)
134 {
135 uint32_t temp;
136
137 if (!regs || (cfg_thrh > MEC5_BDP_CFG_FIFO_THRES_30)) {
138 return MEC_RET_ERR_INVAL;
139 }
140
141 temp = (cfg_thrh & MEC5_BDP_CFG_FIFO_THRES_MSK) >> MEC5_BDP_CFG_FIFO_THRES_POS;
142 regs->CONFIG = (regs->CONFIG & (uint32_t)~(MEC_BDP_CFG_REG_FIFO_THRH_MSK))
143 | ((temp << MEC_BDP_CFG_REG_FIFO_THRH_POS) & MEC_BDP_CFG_REG_FIFO_THRH_MSK);
144
145 return MEC_RET_OK;
146 }
147
148 const uint8_t fifo_cfg_xlat[] = {
149 1u, 4u, 8u, 16u, 20u, 24u, 28u, 30u
150 };
151
mec_hal_bdp_fifo_thresh_get(struct mec_bdp_regs * regs)152 uint32_t mec_hal_bdp_fifo_thresh_get(struct mec_bdp_regs *regs)
153 {
154 if (!regs) {
155 return 0;
156 }
157
158 uint32_t val =
159 (regs->CONFIG & MEC_BDP_CFG_REG_FIFO_THRH_MSK) >> MEC_BDP_CFG_REG_FIFO_THRH_POS;
160
161 return fifo_cfg_xlat[val];
162 }
163
164 /* The only interrupt is THRES_STAT. */
mec_hal_bdp_intr_en(struct mec_bdp_regs * regs,uint8_t enable)165 void mec_hal_bdp_intr_en(struct mec_bdp_regs *regs, uint8_t enable)
166 {
167 if (enable) {
168 regs->IEN |= MEC_BIT(MEC_BDP_INTR_EN_THRES_POS);
169 } else {
170 regs->IEN &= (uint8_t)~MEC_BIT(MEC_BDP_INTR_EN_THRES_POS);
171 }
172 }
173
174 /* All BDP status bits are read-only
175 * STATUS bit[0] NOT_EMPTY is 1 if data in FIFO. 0 if FIFO empty.
176 * STATUS bit[1] OVERRUN is 1 when Host writes data while FIFO is full.
177 * Cleared by reading or flushing FIFO.
178 * STATUS bit[2] THRES_STAT is 1 when number of FIFO entries is >= threshold
179 * Cleared by reading FIFO to below threshold,
180 * OR flushing FIFO
181 * OR increasing FIFO threshold
182 */
mec_hal_bdp_status(struct mec_bdp_regs * regs)183 uint32_t mec_hal_bdp_status(struct mec_bdp_regs *regs)
184 {
185 return regs->STATUS;
186 }
187
mec_hal_bdp_snapshot(struct mec_bdp_regs * regs)188 uint32_t mec_hal_bdp_snapshot(struct mec_bdp_regs *regs)
189 {
190 return regs->SNAP;
191 }
192
193 /* BDP breaks up each 16-bit and 32-bit Host I/O write into separate
194 * FIFO entries for each byte lane. Each FIFO entry is 16-bits composed of
195 * 8-bit data from the byte lane and 8-bits of flags indicating the byte lane
196 * and other info. We don't want to expose this directly to the application.
197 * Processing: Reading the HW FIFO removes the entry.
198 * Len:Lane b[3:2, 1:0]
199 * 0000b 8-bit at lane 0
200 * 0001b 8-bit at lane 1 may be continuation of multi-byte
201 * 0010b 8-bit at lane 2 may be continuation of multi-byte
202 * 0011b 8-bit at lane 3 may be continuation of multi-byte
203 * 0100b 16-bit first byte, starting at lane 0
204 * 0101b 16-bit first byte, starting at lane 1 (misaligned)
205 * 0110b 16-bit first byte, starting at lane 2
206 * 0111b 16/32-bit first byte at lane 3 misaligned, upper bytes lost.
207 * 1000b 32-bit first byte at lane 0
208 * 1001b 32-bit first byte at lane 1 misaligned, byte 3 lost.
209 * 1010b 32-bit first byte at lane 2, upper two bytes lost.
210 * 1011b 32-bit first byte at lane 3, upper three bytes lost.
211 * 11xxb Invalid byte, discard.
212 * If OVERRUN status set, discard any multi-byte value being constructed.
213 *
214 * 16-bit write to lane 0
215 * 0x54_xx, 0x51_xx
216 *
217 * 16-bit write to lane 2
218 * 0x56_xx, 0x53_xx
219 *
220 * 32-bit write to lane 0: 4 FIFO entries
221 * 0x58_xx, 0x51_xx, 0x52_xx, 0x53_xx
222 *
223 *
224 * API to get Host I/O cycles: data and bitmap of byte lanes
225 *
226 */
mec_hal_bdp_get_host_io(struct mec_bdp_regs * regs,struct mec_bdp_io * capio)227 int mec_hal_bdp_get_host_io(struct mec_bdp_regs *regs, struct mec_bdp_io *capio)
228 {
229 uint32_t iodata[4] = {0};
230 uint32_t da = 0u;
231 uint8_t iosize = 0u, blane = 0u, ioflags = 0u, iowidth = 0u;
232
233 if (!regs || !capio) {
234 return MEC_RET_ERR_INVAL;
235 }
236
237 capio->data = 0;
238 capio->flags = 0;
239
240 da = regs->DATRB;
241
242 while (da & MEC_BIT(MEC_BDP_DATRB_NOT_EMPTY_Pos)) {
243 iosize = (uint8_t)((da & MEC_BDP_DATRB_LEN_Msk) >> MEC_BDP_DATRB_LEN_Pos);
244 blane = (uint8_t)((da & MEC_BDP_DATRB_LANE_Msk) >> MEC_BDP_DATRB_LANE_Pos);
245
246 if (iosize == MEC_BDP_DATRB_LEN_IO8) {
247 iodata[blane] = da & 0xffu;
248 ioflags |= MEC_BIT(blane);
249 if (iowidth == 0) { /* single 8-bit I/O write */
250 iowidth = 1;
251 break;
252 } else if (iowidth == 2) {
253 break;
254 } else if ((iowidth == 4) && (blane == 3u)) {
255 break;
256 }
257 } else if (iosize == MEC_BDP_DATRB_LEN_IO16B0) { /* first byte of 16-bit Host I/O write */
258 iowidth = 2u;
259 iodata[blane] = da & 0xffu;
260 ioflags |= MEC_BIT(blane);
261 } else if (iosize == MEC_BDP_DATRB_LEN_IO32B0) { /* first byte of 32-bit Host I/O write */
262 iowidth = 4u;
263 iodata[blane] = da & 0xffu;
264 ioflags |= MEC_BIT(blane);
265 } else { /* invalid and discard */
266 ioflags &= (uint8_t)~MEC_BIT(blane);
267 break;
268 }
269
270 da = regs->DATRB;
271 }
272
273 for (uint8_t n = 0; n < 4; n++) {
274 capio->data <<= 8;
275 capio->data |= iodata[3u - n];
276 }
277
278 capio->flags = ioflags & 0xfu;
279 capio->flags |= ((iowidth << 4) & 0xf0);
280
281 return 0;
282 }
283
284 /* end mec_bdp.c */
285