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