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_pcfg.h"
11 #include "mec_defs.h"
12 #include "mec_ecia_api.h"
13 #include "mec_ecs_api.h"
14 #include "mec_pcr_api.h"
15 #include "mec_peci_api.h"
16 #include "mec_retval.h"
17 
18 #define MEC_PECI_GIRQ               17
19 #define MEC_PECI_GIRQ_POS           0
20 #define MEC_PECI_GIRQ_NVIC          9
21 #define MEC_PECI_GIRQ_NVIC_DIRECT   70
22 
23 #define MEC_PECI_ECIA_INFO MEC5_ECIA_INFO(MEC_PECI_GIRQ, MEC_PECI_GIRQ_POS, \
24                                           MEC_PECI_GIRQ_NVIC, MEC_PECI_GIRQ_NVIC_DIRECT)
25 
26 #define MEC_PECI_OPT_BIT_TIME_MIN 0x0010u
27 #define MEC_PECI_OPT_BIT_TIME_MAX 0xffffu
28 
peci_reset(struct mec_peci_regs * regs)29 static void peci_reset(struct mec_peci_regs *regs)
30 {
31     regs->CTRL = (MEC_BIT(MEC_PECI_CTRL_RST_Pos) | MEC_BIT(MEC_PECI_CTRL_FRST_Pos)
32                   | MEC_BIT(MEC_PECI_CTRL_PWRDN_Pos));
33     regs->IEN1 = 0u;
34     regs->IEN2 = 0u;
35     regs->STATUS1 = UINT8_MAX;
36     regs->STATUS1 = UINT8_MAX;
37     regs->CTRL = MEC_BIT(MEC_PECI_CTRL_PWRDN_Pos);
38 }
39 
peci_girq_dis_clr(void)40 static void peci_girq_dis_clr(void)
41 {
42     mec_hal_girq_ctrl(MEC_PECI_ECIA_INFO, 0);
43     mec_hal_girq_clr_src(MEC_PECI_ECIA_INFO);
44 }
45 
peci_intr_en(struct mec_peci_regs * regs,uint16_t ien_bitmap)46 static void peci_intr_en(struct mec_peci_regs *regs, uint16_t ien_bitmap)
47 {
48     if (!ien_bitmap) {
49         return;
50     }
51 
52     regs->IEN1 |= (uint8_t)(ien_bitmap & 0xffu);
53     regs->IEN2 |= (uint8_t)((ien_bitmap >> 8) & 0xffu);
54 }
55 
56 /* ---- Public API ---- */
57 
58 /* Initialize the key scan controller */
mec_hal_peci_init(struct mec_peci_regs * regs,struct mec_peci_config * cfg,uint32_t flags)59 int mec_hal_peci_init(struct mec_peci_regs *regs, struct mec_peci_config *cfg, uint32_t flags)
60 {
61 #ifdef MEC_PECI_BASE_CHECK
62     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
63         return MEC_RET_ERR_INVAL;
64     }
65 #endif
66 
67     if (!cfg) {
68         return MEC_RET_ERR_INVAL;
69     }
70 
71     mec_hal_ecs_peci_vtt_ref_pin_ctrl(1);
72 
73     mec_hal_pcr_clr_blk_slp_en(MEC_PCR_PECI);
74     if (flags & MEC_PECI_CFG_RESET) {
75         peci_reset(regs);
76     }
77 
78     peci_girq_dis_clr();
79 
80     /* timing */
81     if (flags & MEC_PECI_CFG_CLK_DIV) {
82         regs->BAUD_CTRL = cfg->clock_div;
83     }
84 
85     if (flags & MEC_PECI_CFG_OBT) {
86         regs->OPTBTM_LO = (uint8_t)(cfg->optimal_bit_time);
87         regs->OPTBTM_HI = (uint8_t)(cfg->optimal_bit_time >> 8);
88     }
89 
90     if (flags & MEC_PECI_CFG_REQ_TIMER) {
91         regs->REQ_TIMER_LSB = (uint8_t)(cfg->request_timer);
92         regs->REQ_TIMER_MSB = (uint8_t)(cfg->request_timer >> 8);
93     }
94 
95     if (flags & MEC_PECI_CFG_DIS_BIT_TIME_CLAMP) {
96         regs->SSTCTL1 |= MEC_BIT(MEC_PECI_SSTCTL1_DNBTC_Pos);
97     }
98 
99     mec_hal_girq_ctrl(MEC_PECI_ECIA_INFO, 1);
100 
101     if (flags & MEC_PECI_CFG_INTR_EN) {
102         peci_intr_en(regs, cfg->intr_enables);
103         regs->CTRL |= MEC_BIT(MEC_PECI_CTRL_MIEN_Pos);
104     }
105 
106     if (flags & MEC_PECI_CFG_ENABLE) {
107         regs->CTRL &= (uint8_t)~MEC_BIT(MEC_PECI_CTRL_PWRDN_Pos);
108     }
109 
110     return MEC_RET_OK;
111 }
112 
mec_hal_peci_enable(struct mec_peci_regs * regs,uint8_t enable)113 int mec_hal_peci_enable(struct mec_peci_regs *regs, uint8_t enable)
114 {
115 #ifdef MEC_PECI_BASE_CHECK
116     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
117         return MEC_RET_ERR_INVAL;
118     }
119 #endif
120 
121     if (enable) {
122         regs->CTRL &= (uint8_t)~MEC_BIT(MEC_PECI_CTRL_PWRDN_Pos);
123     } else {
124         regs->CTRL |= MEC_BIT(MEC_PECI_CTRL_PWRDN_Pos);
125     }
126 
127     return MEC_RET_OK;
128 }
129 
mec_hal_peci_ctrl_reset(struct mec_peci_regs * regs,uint8_t assert_reset)130 int mec_hal_peci_ctrl_reset(struct mec_peci_regs *regs, uint8_t assert_reset)
131 {
132 #ifdef MEC_PECI_BASE_CHECK
133     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
134         return MEC_RET_ERR_INVAL;
135     }
136 #endif
137 
138     if (assert_reset) {
139         regs->CTRL |= MEC_BIT(MEC_PECI_CTRL_RST_Pos);
140     } else {
141         regs->CTRL &= (uint8_t)~MEC_BIT(MEC_PECI_CTRL_RST_Pos);
142     }
143 
144     return MEC_RET_OK;
145 }
146 
mec_hal_peci_fifo_reset(struct mec_peci_regs * regs,uint8_t assert_reset)147 int mec_hal_peci_fifo_reset(struct mec_peci_regs *regs, uint8_t assert_reset)
148 {
149 #ifdef MEC_PECI_BASE_CHECK
150     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
151         return MEC_RET_ERR_INVAL;
152     }
153 #endif
154 
155     if (assert_reset) {
156         regs->CTRL |= MEC_BIT(MEC_PECI_CTRL_FRST_Pos);
157     } else {
158         regs->CTRL &= (uint8_t)~MEC_BIT(MEC_PECI_CTRL_FRST_Pos);
159     }
160 
161     return MEC_RET_OK;
162 }
163 
164 /* PECI global interrupt enable.
165  * Must be set after other lower level interrupts are enabled.
166  */
mec_hal_peci_global_ien(struct mec_peci_regs * regs,uint8_t enable)167 int mec_hal_peci_global_ien(struct mec_peci_regs *regs, uint8_t enable)
168 {
169 #ifdef MEC_PECI_BASE_CHECK
170     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
171         return MEC_RET_ERR_INVAL;
172     }
173 #endif
174 
175     if (enable) {
176         regs->CTRL |= MEC_BIT(MEC_PECI_CTRL_MIEN_Pos);
177     } else {
178         regs->CTRL &= (uint8_t)~MEC_BIT(MEC_PECI_CTRL_MIEN_Pos);
179     }
180 
181     return MEC_RET_OK;
182 }
183 
184 /* Enable or disable selected low level PECI interrupts
185  * Note: does not touch global interrupt enable.
186  */
mec_hal_peci_intr_ctrl(struct mec_peci_regs * regs,uint8_t enable,uint16_t intr_bitmap)187 int mec_hal_peci_intr_ctrl(struct mec_peci_regs *regs, uint8_t enable, uint16_t intr_bitmap)
188 {
189 #ifdef MEC_PECI_BASE_CHECK
190     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
191         return MEC_RET_ERR_INVAL;
192     }
193 #endif
194 
195     if (enable) {
196         regs->IEN1 |= (uint8_t)intr_bitmap;
197         regs->IEN2 |= (uint8_t)(intr_bitmap >> 8);
198     } else {
199         regs->IEN1 &= (uint8_t)~intr_bitmap;
200         regs->IEN2 &= (uint8_t)~(intr_bitmap >> 8);
201     }
202 
203     return MEC_RET_OK;
204 }
205 
mec_hal_peci_set_opt_bit_time(struct mec_peci_regs * regs,uint16_t opt_bit_time)206 int mec_hal_peci_set_opt_bit_time(struct mec_peci_regs *regs, uint16_t opt_bit_time)
207 {
208 #ifdef MEC_PECI_BASE_CHECK
209     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
210         return MEC_RET_ERR_INVAL;
211     }
212 #endif
213 
214     if (opt_bit_time < MEC_PECI_OPT_BIT_TIME_MIN) {
215         return MEC_RET_ERR_INVAL;
216     }
217 
218     uint8_t ctrl = regs->CTRL;
219 
220     regs->CTRL = ctrl | MEC_BIT(MEC_PECI_CTRL_PWRDN_Pos);
221     regs->OPTBTM_LO = (uint8_t)opt_bit_time;
222     regs->OPTBTM_HI = (uint8_t)(opt_bit_time >> 8);
223     regs->CTRL = ctrl;
224 
225     return MEC_RET_OK;
226 }
227 
228 /* Set PECI transmit enable. Hardware clears transmit enable when it
229  * received the End-Of-Frame (EOF) and sets EOF status.
230  */
mec_hal_peci_tx_enable(struct mec_peci_regs * regs,uint8_t enable)231 int mec_hal_peci_tx_enable(struct mec_peci_regs *regs, uint8_t enable)
232 {
233 #ifdef MEC_PECI_BASE_CHECK
234     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
235         return MEC_RET_ERR_INVAL;
236     }
237 #endif
238 
239     if (enable) {
240         regs->CTRL |= MEC_BIT(MEC_PECI_CTRL_TXEN_Pos);
241     } else {
242         regs->CTRL &= (uint8_t)~MEC_BIT(MEC_PECI_CTRL_TXEN_Pos);
243     }
244 
245     return MEC_RET_OK;
246 }
247 
mec_hal_peci_status(struct mec_peci_regs * regs)248 uint32_t mec_hal_peci_status(struct mec_peci_regs *regs)
249 {
250 #ifdef MEC_PECI_BASE_CHECK
251     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
252         return 0;
253     }
254 #endif
255 
256     uint32_t sts = regs->STATUS1;
257 
258     sts |= ((uint32_t)regs->STATUS2 << 8);
259     sts |= ((uint32_t)regs->ERROR << 16);
260 
261     return sts;
262 }
263 
264 /* PECI status1 has a bit set by any bit active in the error status register.
265  * We must clear error status first.
266  * PECI status2 is read-only
267  */
mec_hal_peci_status_clear(struct mec_peci_regs * regs,uint32_t sts)268 uint32_t mec_hal_peci_status_clear(struct mec_peci_regs *regs, uint32_t sts)
269 {
270 #ifdef MEC_PECI_BASE_CHECK
271     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
272         return 0;
273     }
274 #endif
275 
276     regs->ERROR = (uint8_t)(sts >> 16);
277     regs->STATUS1 = (uint8_t)sts;
278 
279     return sts;
280 }
281 
mec_hal_peci_girq_en(struct mec_peci_regs * regs)282 int mec_hal_peci_girq_en(struct mec_peci_regs *regs)
283 {
284 #ifdef MEC_PECI_BASE_CHECK
285     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
286         return MEC_RET_ERR_INVAL;
287     }
288 #else
289     (void)regs;
290 #endif
291 
292     mec_hal_girq_ctrl(MEC_PECI_ECIA_INFO, 1);
293 
294     return MEC_RET_OK;
295 }
296 
mec_hal_peci_girq_dis(struct mec_peci_regs * regs)297 int mec_hal_peci_girq_dis(struct mec_peci_regs *regs)
298 {
299 #ifdef MEC_PECI_BASE_CHECK
300     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
301         return MEC_RET_ERR_INVAL;
302     }
303 #else
304     (void)regs;
305 #endif
306 
307     mec_hal_girq_ctrl(MEC_PECI_ECIA_INFO, 0);
308 
309     return MEC_RET_OK;
310 }
311 
mec_hal_peci_girq_clr(struct mec_peci_regs * regs)312 int mec_hal_peci_girq_clr(struct mec_peci_regs *regs)
313 {
314 #ifdef MEC_PECI_BASE_CHECK
315     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
316         return MEC_RET_ERR_INVAL;
317     }
318 #else
319     (void)regs;
320 #endif
321 
322     mec_hal_girq_clr_src(MEC_PECI_ECIA_INFO);
323 
324     return MEC_RET_OK;
325 }
326 
mec_hal_peci_girq_result(struct mec_peci_regs * regs)327 uint32_t mec_hal_peci_girq_result(struct mec_peci_regs *regs)
328 {
329 #ifdef MEC_PECI_BASE_CHECK
330     if ((uintptr_t)regs != (uintptr_t)MEC_PECI0_BASE) {
331         return MEC_RET_ERR_INVAL;
332     }
333 #else
334     (void)regs;
335 #endif
336 
337     return mec_hal_girq_result(MEC_PECI_ECIA_INFO);
338 }
339 
340 /* ---- Power Management ---- */
341 
342 #define MEC_PECI_PM_SAVE_ITEMS_CNT 2
343 static uint8_t peci_pm_save_buf[MEC_PECI_PM_SAVE_ITEMS_CNT];
344 
mec_hal_peci_pm_save_disable(void)345 void mec_hal_peci_pm_save_disable(void)
346 {
347     peci_pm_save_buf[0] = MEC_PECI0->CTRL;
348     MEC_PECI0->CTRL |= MEC_BIT(MEC_PECI_CTRL_PWRDN_Pos);
349 
350     if (mec_hal_ecs_peci_vtt_ref_pin_is_enabled()) {
351         peci_pm_save_buf[1] = 1;
352     }
353 
354     mec_hal_ecs_peci_vtt_ref_pin_ctrl(0);
355 }
356 
mec_hal_peci_pm_save_restore(void)357 void mec_hal_peci_pm_save_restore(void)
358 {
359     if (peci_pm_save_buf[1]) {
360         mec_hal_ecs_peci_vtt_ref_pin_ctrl(1);
361     }
362 
363     MEC_PECI0->CTRL = peci_pm_save_buf[0];
364 }
365 
366 /* end mec_peci.c */
367