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_pcr_api.h"
14 #include "mec_kbc_api.h"
15 #include "mec_retval.h"
16 
17 #define MEC_KBC_GIRQ         15
18 #define MEC_KBC_OBE_GIRQ_POS 18
19 #define MEC_KBC_IBF_GIRQ_POS 19
20 
21 #define MEC_KBC_OBE_ECIA_INFO MEC5_ECIA_INFO(15, 18, 7, 58)
22 #define MEC_KBC_IBF_ECIA_INFO MEC5_ECIA_INFO(15, 19, 7, 60)
23 
24 #define MEC_KBC_OBE_DEVI_IDX 0
25 #define MEC_KBC_IBF_DEVI_IDX 1
26 
port92h_ctrl(uint8_t enable)27 static void port92h_ctrl(uint8_t enable)
28 {
29     struct mec_port92_regs *regs = (struct mec_port92_regs *)MEC_PORT92_BASE;
30 
31     if (enable) {
32         regs->P92ACT |= MEC_BIT(MEC_PORT92_P92ACT_ENABLE_Pos);
33     } else {
34         regs->P92ACT &= (uint8_t)~MEC_BIT(MEC_PORT92_P92ACT_ENABLE_Pos);
35     }
36 }
37 
38 /* KBC EC-only registers
39  * Host-to-EC Data (RO) returns data written by Host to Data/Cmd registers
40  * EC Data (WO)
41  * EC KB status (RW except OBF, IBF, and CD)
42  * KB Control RW
43  * EC AUX Data (WO). Writes clear CD bit and set IBF in KB Status
44  * PCOBF bit[0] is PCOBF (RW) cleared when Host reads Data or AUX Data.
45  */
46 
47 /* ---- Public API ---- */
48 
49 /* Initialize EM8042 keyboard controller.
50  * This peripheral is reset by chip reset (RESET_SYS), host power rail reset
51  * (RESET_VCC), or host reset signal (PCI_RESET# or PLTRST#).
52  * RESET_VCC can be EC firmware controlled via the PWR_INV bit in the
53  * PCR Reset Control register.
54  * EM8042 keyboard controller has two interrupt signals: KIRQ and MIRQ
55  * connected to individual GIRQ15 bits and to individual NVIC inputs.
56  * If direct NVIC interrupt mode is used, we can ignore the GIRQ15 KIRQ
57  * and MIRQ status bits. Only the GIRQ enables matter.
58  * KIRQ and MIRQ control in the KBC is not independent.
59  * KBC.Control.OBFEN = 0 HW drivers both KIRQ and MIRQ low (inactive).
60  * KBC.Control.OBFEN = 1 enables KBC to assert both KIRQ and MIRQ.
61  * We can individually enable/disable KIRQ and MIRQ using the GIRQ enable bits.
62  * KBC.Control.PCOBFEN selects the event causing KIRQ to assert.
63  *  PCOBFEN = 0. KIRQ goes active on writes to Host-to-EC Data register.
64  *  PCOBFEN = 1. KIRQ goes active on writes to PCOBF register.
65  * KBC.Control.AUXH selects the event causing MIRQ to assert.
66  *  AUXH = 0. MIRQ goes active on writes to EC AUX Data register.
67  *  AUXH = 1. MIRQ goes active on writes to AUXOBF bit in EC KB Status register.
68  */
mec_hal_kbc_init(struct mec_kbc_regs * base,uint32_t flags)69 int mec_hal_kbc_init(struct mec_kbc_regs *base, uint32_t flags)
70 {
71     uint8_t ctrl = 0u, msk = 0u, val = 0u;
72 
73     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
74         return MEC_RET_ERR_INVAL;
75     }
76 
77     mec_hal_pcr_clr_blk_slp_en(MEC_PCR_KBC0);
78     if (flags & MEC_KBC_RESET) {
79         mec_hal_pcr_blk_reset(MEC_PCR_KBC0);
80     } else {
81         base->ACTV &= (uint8_t)~MEC_BIT(MEC_KBC_ACTV_ENABLE_Pos);
82     }
83 
84     mec_hal_kbc_girq_dis(base, MEC_KBC_IBF_IRQ | MEC_KBC_OBE_IRQ);
85     mec_hal_kbc_girq_clr(base, MEC_KBC_IBF_IRQ | MEC_KBC_OBE_IRQ);
86 
87     val = (flags & MEC_KBC_PORT92_EN) ? 1 : 0;
88     port92h_ctrl(val);
89 
90     if (flags & MEC_KBC_GATEA20_FWC_EN) {
91         ctrl |= MEC_BIT(MEC_KBC_KECR_SAEN_Pos);
92     }
93 
94     if (flags & (MEC_KBC_IBF_IRQ | MEC_KBC_OBE_IRQ)) {
95         ctrl |= MEC_BIT(MEC_KBC_KECR_OBFEN_Pos);
96     }
97 
98     if (flags & MEC_KBC_PCOBF_EN) {
99         ctrl |= MEC_BIT(MEC_KBC_KECR_PCOBFEN_Pos);
100     }
101     if (flags & MEC_KBC_AUXOBF_EN) {
102         ctrl |= MEC_BIT(MEC_KBC_KECR_AUXH_Pos);
103     }
104 
105     if (flags & MEC_KBC_UD3_SET) {
106         if (flags & MEC_KBC_UD3_ONE) {
107             ctrl |= MEC_BIT(MEC_KBC_KECR_UD3_Pos);
108         }
109     }
110 
111     if (flags & MEC_KBC_UD4_SET) {
112         if (flags & MEC_KBC_UD4_0_ONE) {
113             ctrl |= MEC_BIT(MEC_KBC_KECR_UD4_Pos);
114         }
115         if (flags & MEC_KBC_UD4_1_ONE) {
116             ctrl |= MEC_BIT(MEC_KBC_KECR_UD4_Pos + 1);
117         }
118     }
119 
120     if (flags & MEC_KBC_UD5_SET) {
121         if (flags & MEC_KBC_UD5_ONE) {
122             ctrl |= MEC_BIT(MEC_KBC_KECR_UD5_Pos);
123         }
124     }
125 
126     if (flags & MEC_KBC_UD0_SET) {
127         msk |= MEC_KBC_KESTATUS_UD0_Msk;
128         if (flags & MEC_KBC_UD0_ONE) {
129             val |= MEC_BIT(MEC_KBC_KESTATUS_UD0_Pos);
130         }
131     }
132 
133     if (flags & MEC_KBC_UD1_SET) {
134         msk |= MEC_KBC_KESTATUS_UD1_Msk;
135         if (flags & MEC_KBC_UD1_SET) {
136             val |= MEC_BIT(MEC_KBC_KESTATUS_UD1_Pos);
137         }
138     }
139 
140     if (flags & MEC_KBC_UD2_SET) {
141         msk |= MEC_KBC_KESTATUS_UD2_Msk;
142         if (flags & MEC_KBC_UD2_0_ONE) {
143             val |= MEC_BIT(MEC_KBC_KESTATUS_UD2_Pos);
144         }
145         if (flags & MEC_KBC_UD2_1_ONE) {
146             val |= MEC_BIT(MEC_KBC_KESTATUS_UD2_Pos + 1);
147         }
148     }
149 
150     if (msk) {
151         base->KESTATUS = (base->KESTATUS & ~msk) | val;
152     }
153 
154     base->KECR = ctrl;
155     base->ACTV |= MEC_BIT(MEC_KBC_ACTV_ENABLE_Pos);
156     mec_hal_kbc_girq_en(base, flags);
157 
158     return MEC_RET_OK;
159 }
160 
mec_hal_kbc_activate(struct mec_kbc_regs * base,uint8_t enable,uint8_t flags)161 int mec_hal_kbc_activate(struct mec_kbc_regs *base, uint8_t enable, uint8_t flags)
162 {
163 #ifdef MEC_KBC_BASE_CHECK
164     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
165         return MEC_RET_ERR_INVAL;
166     }
167 #endif
168 
169     if (flags & MEC_KBC_ACTV_P92) {
170         port92h_ctrl(enable);
171     }
172 
173     if (flags & MEC_KBC_ACTV_KBC) {
174         if (enable) {
175             base->ACTV |= MEC_BIT(MEC_KBC_ACTV_ENABLE_Pos);
176         } else {
177             base->ACTV &= (uint8_t)~MEC_BIT(MEC_KBC_ACTV_ENABLE_Pos);
178         }
179     }
180 
181     return MEC_RET_OK;
182 }
183 
kbc_irq_bitmap(uint32_t flags)184 static uint32_t kbc_irq_bitmap(uint32_t flags)
185 {
186     uint32_t bm = 0;
187 
188     if (flags & MEC_KBC_IBF_IRQ) {
189         bm |= MEC_BIT(MEC_KBC_IBF_GIRQ_POS);
190     }
191 
192     if (flags & MEC_KBC_OBE_IRQ) {
193         bm |= MEC_BIT(MEC_KBC_OBE_GIRQ_POS);
194     }
195 
196     return bm;
197 }
198 
mec_hal_kbc_girq_en(struct mec_kbc_regs * base,uint32_t flags)199 int mec_hal_kbc_girq_en(struct mec_kbc_regs *base, uint32_t flags)
200 {
201 #ifdef MEC_KBC_BASE_CHECK
202     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
203         return MEC_RET_ERR_INVAL;
204     }
205 #else
206     (void)base;
207 #endif
208 
209     uint32_t en_bitmap = kbc_irq_bitmap(flags);
210 
211     mec_hal_girq_bm_en(MEC_KBC_GIRQ, en_bitmap, 1u);
212 
213     return MEC_RET_OK;
214 }
215 
mec_hal_kbc_girq_dis(struct mec_kbc_regs * base,uint32_t flags)216 int mec_hal_kbc_girq_dis(struct mec_kbc_regs *base, uint32_t flags)
217 {
218 #ifdef MEC_KBC_BASE_CHECK
219     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
220         return MEC_RET_ERR_INVAL;
221     }
222 #else
223     (void)base;
224 #endif
225 
226     uint32_t dis_bitmap = kbc_irq_bitmap(flags);
227 
228     mec_hal_girq_bm_en(MEC_KBC_GIRQ, dis_bitmap, 0);
229 
230     return MEC_RET_OK;
231 }
232 
mec_hal_kbc_girq_clr(struct mec_kbc_regs * base,uint32_t flags)233 int mec_hal_kbc_girq_clr(struct mec_kbc_regs *base, uint32_t flags)
234 {
235 #ifdef MEC_KBC_BASE_CHECK
236     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
237         return MEC_RET_ERR_INVAL;
238     }
239 #else
240     (void)base;
241 #endif
242 
243     uint32_t clr_bitmap = kbc_irq_bitmap(flags);
244 
245     mec_hal_girq_bm_clr_src(MEC_KBC_GIRQ, clr_bitmap);
246 
247     return MEC_RET_OK;
248 }
249 
mec_kbc_girq_result(struct mec_kbc_regs * base)250 uint32_t mec_kbc_girq_result(struct mec_kbc_regs *base)
251 {
252     uint32_t temp = 0u, result = 0u;
253 
254 #ifdef MEC_KBC_BASE_CHECK
255     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
256         return 0;
257     }
258 #else
259     (void)base;
260 #endif
261 
262     temp = mec_hal_girq_result_get(MEC_KBC_GIRQ);
263     if (temp & MEC_BIT(MEC_KBC_IBF_GIRQ_POS)) {
264         result |= MEC_KBC_IBF_IRQ;
265     }
266     if (temp & MEC_BIT(MEC_KBC_OBE_GIRQ_POS)) {
267         result |= MEC_KBC_OBE_IRQ;
268     }
269 
270     return result;
271 }
272 
mec_hal_kbc_is_enabled(struct mec_kbc_regs * base)273 int mec_hal_kbc_is_enabled(struct mec_kbc_regs *base)
274 {
275 #ifdef MEC_KBC_BASE_CHECK
276     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
277         return 0;
278     }
279 #endif
280 
281     if (base->ACTV & MEC_BIT(MEC_KBC_ACTV_ENABLE_Pos)) {
282         return 1;
283     }
284 
285     return 0;
286 }
287 
mec_hal_kbc_is_irq_gen_enabled(struct mec_kbc_regs * base)288 int mec_hal_kbc_is_irq_gen_enabled(struct mec_kbc_regs *base)
289 {
290 #ifdef MEC_KBC_BASE_CHECK
291     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
292         return 0;
293     }
294 #endif
295 
296     if (base->KECR & MEC_BIT(MEC_KBC_KECR_OBFEN_Pos)) {
297         return 1;
298     }
299 
300     return 0;
301 }
302 
mec_hal_kbc_status(struct mec_kbc_regs * base)303 uint8_t mec_hal_kbc_status(struct mec_kbc_regs *base)
304 {
305 #ifdef MEC_KBC_BASE_CHECK
306     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
307         return 0;
308     }
309 #endif
310 
311     return base->KESTATUS;
312 }
313 
mec_hal_kbc_status_wr(struct mec_kbc_regs * base,uint8_t val,uint8_t msk)314 void mec_hal_kbc_status_wr(struct mec_kbc_regs *base, uint8_t val, uint8_t msk)
315 {
316 #ifdef MEC_KBC_BASE_CHECK
317     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
318         return;
319     }
320 #endif
321 
322     base->KESTATUS = (base->KESTATUS & ~msk) | (val & msk);
323 }
324 
mec_hal_kbc_status_set(struct mec_kbc_regs * base,uint8_t msk)325 void mec_hal_kbc_status_set(struct mec_kbc_regs *base, uint8_t msk)
326 {
327 #ifdef MEC_KBC_BASE_CHECK
328     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
329         return;
330     }
331 #endif
332 
333     base->KESTATUS |= msk;
334 }
335 
mec_hal_kbc_status_clear(struct mec_kbc_regs * base,uint8_t msk)336 void mec_hal_kbc_status_clear(struct mec_kbc_regs *base, uint8_t msk)
337 {
338 #ifdef MEC_KBC_BASE_CHECK
339     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
340         return;
341     }
342 #endif
343 
344     base->KESTATUS &= (uint8_t)~msk;
345 }
346 
mec_hal_kbc_wr_data(struct mec_kbc_regs * base,uint8_t data,uint8_t data_is_aux)347 void mec_hal_kbc_wr_data(struct mec_kbc_regs *base, uint8_t data, uint8_t data_is_aux)
348 {
349 #ifdef MEC_KBC_BASE_CHECK
350     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
351         return;
352     }
353 #endif
354 
355     if (data_is_aux) {
356         base->KEAUXD = data;
357     } else {
358         base->KHECD = data;
359     }
360 }
361 
mec_hal_kbc_rd_host_data(struct mec_kbc_regs * base,uint8_t is_host_data_reg)362 uint8_t mec_hal_kbc_rd_host_data(struct mec_kbc_regs *base, uint8_t is_host_data_reg)
363 {
364 #ifdef MEC_KBC_BASE_CHECK
365     if ((uintptr_t)base != (uintptr_t)MEC_KBC0_BASE) {
366         return MEC_RET_ERR_INVAL;
367     }
368 #endif
369 
370     if (!is_host_data_reg) {
371         return base->KHECD;
372     } else {
373         return base->KHDATA;
374     }
375 }
376 
377 /* end mec_kbc.c */
378