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