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_ecia_api.h"
12 #include "mec_pcr_api.h"
13 #include "mec_ps2_api.h"
14
15 #if MEC5_PS2_INSTANCES
16
17 #define MEC_PS2_CTRL_BITMAP MEC_GENMASK(MEC5_PS2_INSTANCES, 0)
18
19 #define MEC_PS2_GIRQ 18
20 #define MEC_PS2_0_GIRQ_POS 10
21 #define MEC_PS2_1_GIRQ_POS 11
22
23 #define MEC_PS2_0_ECIA_INFO MEC5_ECIA_INFO(18, 10, 10, 100)
24 #define MEC_PS2_1_ECIA_INFO MEC5_ECIA_INFO(18, 11, 10, 101)
25
26 /* PS/2 port wake event: start bit detection
27 * NOTE: PS/2 ports are separate pins and the controller can only be
28 * connected to one port at a time. Each port is two pins: clock and data.
29 * MEC5 PS/2 Controller 0 implements two ports.
30 * MEC5 PS/2 Controller 1 implements one port.
31 */
32 #define MEC_PS2_WAKE_GIRQ 21
33 #define MEC_PS2_WAKE_0A_GIRQ_POS 18 /* Controller 0 Port A */
34 #define MEC_PS2_WAKE_0B_GIRQ_POS 19 /* Controller 0 Port B */
35 #define MEC_PS2_WAKE_1B_GIRQ_POS 21 /* Controller 1 Port B */
36
37 #define MEC_PS2_WAKE_0A_ECIA_INFO MEC5_ECIA_INFO(21, 13, 18, 129)
38 #define MEC_PS2_WAKE_0B_ECIA_INFO MEC5_ECIA_INFO(21, 13, 19, 130)
39 #define MEC_PS2_WAKE_1B_ECIA_INFO MEC5_ECIA_INFO(21, 13, 21, 132)
40
41 struct mec_ps2_info {
42 uintptr_t base_addr;
43 uint16_t pcr_id;
44 uint8_t port_map;
45 uint8_t rsvd1;
46 uint32_t devi;
47 uint32_t port_a_wake_devi;
48 uint32_t port_b_wake_devi;
49 };
50
51 static const struct mec_ps2_info ps2_instances[MEC5_PS2_INSTANCES] = {
52 { MEC_PS2CTL0_BASE, (uint16_t)MEC_PCR_PS2_0, 0x3u, 0, MEC_PS2_0_ECIA_INFO,
53 MEC_PS2_WAKE_0A_ECIA_INFO, MEC_PS2_WAKE_0B_ECIA_INFO },
54 #if MEC5_PS2_INSTANCES > 1
55 { MEC_PS2CTL1_BASE, (uint16_t)MEC_PCR_PS2_1, 0x2u, 0, MEC_PS2_1_ECIA_INFO,
56 MEC_PS2_WAKE_1B_ECIA_INFO, UINT32_MAX },
57 #endif
58 };
59
find_ps2_info(uintptr_t base_addr)60 static struct mec_ps2_info const *find_ps2_info(uintptr_t base_addr)
61 {
62 for (size_t i = 0; i < MEC5_PS2_INSTANCES; i++) {
63 if (base_addr == ps2_instances[i].base_addr) {
64 return &ps2_instances[i];
65 }
66 }
67
68 return NULL;
69 }
70
ps2_clear_all_status(struct mec_ps2_regs * regs)71 static void ps2_clear_all_status(struct mec_ps2_regs *regs)
72 {
73 /* read and discard data to clear RX_RDY RO status */
74 regs->STATUS = regs->RTXB | (MEC_BIT(MEC_PS2_STATUS_RXTMO_Pos)
75 | MEC_BIT(MEC_PS2_STATUS_PE_Pos)
76 | MEC_BIT(MEC_PS2_STATUS_FE_Pos)
77 | MEC_BIT(MEC_PS2_STATUS_TXTMO_Pos)
78 | MEC_BIT(MEC_PS2_STATUS_TXSTTMO_Pos));
79 }
80
81 /* PS/2 registers (not visible to the Host)
82 * Transmit buffer 8-bit W/O
83 * Receive data 8-bit R/O
84 * Control 8-bit R/W
85 * Status 8-bit mix of R/O and R/W1C bits.
86 *
87 * Writes to TX buffer triggers transmission unless the receive buffer is full.
88 * Once the receive data register is read and RDATA_RDY R/O status has cleared
89 * the pending transmit will begin.
90 */
91
ps2_is_enabled(struct mec_ps2_regs * regs)92 static bool ps2_is_enabled(struct mec_ps2_regs *regs)
93 {
94 if (regs->CTRL & MEC_BIT(MEC_PS2_CTRL_ENABLE_Pos)) {
95 return true;
96 }
97
98 return false;
99 }
100
101 /* ---- Public API ---- */
102
mec_hal_ps2_init(struct mec_ps2_regs * regs,uint32_t flags)103 int mec_hal_ps2_init(struct mec_ps2_regs *regs, uint32_t flags)
104 {
105 const struct mec_ps2_info *psi = find_ps2_info((uint32_t)regs);
106 uint32_t temp = 0u;
107 uint8_t ctrl = 0u;
108
109 if (!psi) {
110 return MEC_RET_ERR_INVAL;
111 }
112
113 mec_hal_pcr_clr_blk_slp_en(psi->pcr_id);
114 if (flags & MEC_PS2_FLAGS_RESET) {
115 mec_hal_pcr_blk_reset(psi->pcr_id);
116 } else {
117 regs->CTRL = 0u;
118 }
119
120 mec_hal_girq_ctrl(psi->devi, 0);
121 mec_hal_girq_clr_src(psi->devi);
122 ps2_clear_all_status(regs);
123
124 temp = ((flags & MEC_PS2_FLAGS_PARITY_MSK) >> MEC_PS2_FLAGS_PARITY_POS);
125 ctrl |= (uint8_t)((temp << MEC_PS2_CTRL_PARITY_Pos) & MEC_PS2_CTRL_PARITY_Msk);
126
127 temp = ((flags & MEC_PS2_FLAGS_STOP_BITS_MSK) >> MEC_PS2_FLAGS_STOP_BITS_POS);
128 ctrl |= (uint8_t)((temp << MEC_PS2_CTRL_STOP_Pos) & MEC_PS2_CTRL_STOP_Msk);
129
130 if (flags & MEC_PS2_FLAGS_ENABLE) {
131 ctrl |= MEC_BIT(MEC_PS2_CTRL_ENABLE_Pos);
132 }
133
134 regs->CTRL = ctrl;
135
136 if (flags & MEC_PS2_FLAGS_INTR_EN) {
137 mec_hal_girq_ctrl(psi->devi, 1);
138 }
139
140 return MEC_RET_OK;
141 }
142
mec_hal_ps2_control(struct mec_ps2_regs * regs,uint8_t operand,uint8_t opmask)143 int mec_hal_ps2_control(struct mec_ps2_regs *regs, uint8_t operand, uint8_t opmask)
144 {
145 const struct mec_ps2_info *psi = find_ps2_info((uint32_t)regs);
146
147 if (!psi) {
148 return MEC_RET_ERR_INVAL;
149 }
150
151 regs->CTRL = (regs->CTRL & (uint8_t)~(opmask & 0x03u)) | (operand & 0x03u);
152
153 return MEC_RET_OK;
154 }
155
mec_hal_ps2_is_enabled(struct mec_ps2_regs * regs)156 bool mec_hal_ps2_is_enabled(struct mec_ps2_regs *regs)
157 {
158 const struct mec_ps2_info *psi = find_ps2_info((uint32_t)regs);
159
160 if (!psi) {
161 return false;
162 }
163
164 return ps2_is_enabled(regs);
165 }
166
mec_hal_ps2_girq_ctrl(struct mec_ps2_regs * base,uint8_t enable)167 int mec_hal_ps2_girq_ctrl(struct mec_ps2_regs *base, uint8_t enable)
168 {
169 const struct mec_ps2_info *psi = find_ps2_info((uint32_t)base);
170
171 if (!psi) {
172 return MEC_RET_ERR_INVAL;
173 }
174
175 mec_hal_girq_ctrl(psi->devi, enable);
176
177 return MEC_RET_OK;
178 }
179
mec_hal_ps2_girq_clr(struct mec_ps2_regs * base)180 int mec_hal_ps2_girq_clr(struct mec_ps2_regs *base)
181 {
182 const struct mec_ps2_info *psi = find_ps2_info((uint32_t)base);
183
184 if (!psi) {
185 return MEC_RET_ERR_INVAL;
186 }
187
188 mec_hal_girq_clr_src(psi->devi);
189
190 return MEC_RET_OK;
191 }
192
mec_hal_ps2_girq_result(struct mec_ps2_regs * base)193 uint32_t mec_hal_ps2_girq_result(struct mec_ps2_regs *base)
194 {
195 const struct mec_ps2_info *psi = find_ps2_info((uint32_t)base);
196
197 if (!psi) {
198 return 0u;
199 }
200
201 return mec_hal_girq_result(psi->devi);
202 }
203
mec_hal_ps2_girq_wake_enable(struct mec_ps2_regs * base,uint8_t port,uint8_t enable)204 int mec_hal_ps2_girq_wake_enable(struct mec_ps2_regs *base, uint8_t port, uint8_t enable)
205 {
206 const struct mec_ps2_info *psi = find_ps2_info((uint32_t)base);
207 uint32_t devi = 0;
208
209 if (!psi || (port >= MEC5_PS2_PORT_MAX)) {
210 return MEC_RET_ERR_INVAL;
211 }
212
213 if ((uint32_t)psi->port_map & MEC_BIT(port)) {
214 return MEC_RET_ERR_INVAL;
215 }
216
217 devi = psi->port_a_wake_devi;
218 if (port == MEC5_PS2_PORT_B) {
219 devi = psi->port_b_wake_devi;
220 }
221
222 mec_hal_girq_ctrl(devi, enable);
223
224 return MEC_RET_OK;
225 }
226
mec_hal_ps2_girq_wake_result(struct mec_ps2_regs * base,uint8_t port)227 uint32_t mec_hal_ps2_girq_wake_result(struct mec_ps2_regs *base, uint8_t port)
228 {
229 const struct mec_ps2_info *psi = find_ps2_info((uint32_t)base);
230
231 if (!psi) {
232 return 0u;
233 }
234
235 if (port == MEC5_PS2_PORT_A) {
236 return mec_hal_girq_result(psi->port_a_wake_devi);
237 } else {
238 return mec_hal_girq_result(psi->port_b_wake_devi);
239 }
240 }
241
mec_hal_ps2_girq_wake_clr(struct mec_ps2_regs * base,uint8_t port)242 void mec_hal_ps2_girq_wake_clr(struct mec_ps2_regs *base, uint8_t port)
243 {
244 const struct mec_ps2_info *psi = find_ps2_info((uint32_t)base);
245 uint32_t devi;
246
247 if (!psi) {
248 return;
249 }
250
251 devi = psi->port_a_wake_devi;
252 if (port != MEC5_PS2_PORT_A) {
253 devi = psi->port_b_wake_devi;
254 }
255
256 mec_hal_girq_clr_src(devi);
257 }
258
mec_hal_ps2_direction(struct mec_ps2_regs * regs,uint8_t dir_tx)259 void mec_hal_ps2_direction(struct mec_ps2_regs *regs, uint8_t dir_tx)
260 {
261 if (dir_tx) {
262 regs->CTRL |= MEC_BIT(MEC_PS2_CTRL_TREN_Pos);
263 } else {
264 regs->CTRL &= (uint8_t)~MEC_BIT(MEC_PS2_CTRL_TREN_Pos);
265 }
266 }
267
mec_hal_ps2_get_status(struct mec_ps2_regs * regs)268 uint32_t mec_hal_ps2_get_status(struct mec_ps2_regs *regs)
269 {
270 return regs->STATUS;
271 }
272
mec_hal_ps2_clr_status(struct mec_ps2_regs * regs,uint32_t clrmsk)273 void mec_hal_ps2_clr_status(struct mec_ps2_regs *regs, uint32_t clrmsk)
274 {
275 regs->STATUS = (uint8_t)(clrmsk & 0xffu);
276 }
277
mec_hal_ps2_read_data(struct mec_ps2_regs * regs)278 uint8_t mec_hal_ps2_read_data(struct mec_ps2_regs *regs)
279 {
280 return regs->RTXB;
281 }
282
mec_hal_ps2_send_data(struct mec_ps2_regs * regs,uint8_t data)283 void mec_hal_ps2_send_data(struct mec_ps2_regs *regs, uint8_t data)
284 {
285 regs->RTXB = data;
286 }
287
mec_hal_ps2_inst_wake_enable(uint8_t instance,uint8_t port,uint8_t enable)288 int mec_hal_ps2_inst_wake_enable(uint8_t instance, uint8_t port, uint8_t enable)
289 {
290 if (instance >= MEC5_PS2_INSTANCES) {
291 return MEC_RET_ERR_INVAL;
292 }
293
294 struct mec_ps2_regs *regs = (struct mec_ps2_regs *)ps2_instances[instance].base_addr;
295 int ret = mec_hal_ps2_girq_wake_enable(regs, port, enable);
296
297 return ret;
298 }
299
mec_hal_ps2_inst_wake_status_clr(uint8_t instance,uint8_t port)300 int mec_hal_ps2_inst_wake_status_clr(uint8_t instance, uint8_t port)
301 {
302 if (instance >= MEC5_PS2_INSTANCES) {
303 return MEC_RET_ERR_INVAL;
304 }
305
306 struct mec_ps2_regs *regs = (struct mec_ps2_regs *)ps2_instances[instance].base_addr;
307
308 mec_hal_ps2_girq_wake_clr(regs, port);
309
310 return MEC_RET_OK;
311 }
312
313 /* void mec_hal_ps2_girq_wake_clr(struct mec_ps2_regs *base, uint8_t port) */
314 /* int ret = mec_hal_ps2_girq_wake_enable(regs, port, enable); */
315
316 /* Enable or disable wake enables for all PS/2 ports on all enabled controllers.
317 * If the port pins are configured for PS/2 mode then the port should not
318 * trigger a wake.
319 */
mec_hal_ps2_wake_enables(uint8_t enable)320 void mec_hal_ps2_wake_enables(uint8_t enable)
321 {
322 for (uint8_t i = 0; i < MEC5_PS2_INSTANCES; i++) {
323 const struct mec_ps2_info *info = &ps2_instances[i];
324 struct mec_ps2_regs *const regs = (struct mec_ps2_regs *)info->base_addr;
325
326 if (ps2_is_enabled(regs)) {
327 if (info->port_map & MEC_BIT(0)) { /* port A? */
328 mec_hal_girq_ctrl(info->port_a_wake_devi, enable);
329 if (!enable) {
330 mec_hal_girq_clr_src(info->port_a_wake_devi);
331 }
332 }
333 if (info->port_map & MEC_BIT(1)) { /* port B? */
334 mec_hal_girq_ctrl(info->port_b_wake_devi, enable);
335 if (!enable) {
336 mec_hal_girq_clr_src(info->port_b_wake_devi);
337 }
338 }
339 }
340 }
341 }
342 #endif /* MEC5_PS2_INSTANCES */
343
344 /* end mec_ps2.c */
345