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