1 /*
2 * Copyright (c) 2020 Nuvoton Technology Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nuvoton_npcx_host_sub
8
9 /**
10 * @file
11 * @brief Nuvoton NPCX host sub modules driver
12 *
13 * This file contains the drivers of NPCX Host Sub-Modules that serve as an
14 * interface between the Host and Core domains. Please refer the block diagram.
15 *
16 * +------------+
17 * | Serial |---> TXD
18 * +<--->| Port |<--- RXD
19 * | | |<--> ...
20 * | +------------+
21 * | +------------+ |
22 * +------------+ |<--->| KBC & PM |<--->|
23 * eSPI_CLK --->| eSPI Bus | | | Channels | |
24 * eSPI_RST --->| Controller | | +------------+ |
25 * eSPI_IO3-0 <-->| |<-->| +------------+ |
26 * eSPI_CS --->| (eSPI mode)| | | Shared | |
27 * eSPI_ALERT <-->| | |<--->| Memory |<--->|
28 * +------------+ | +------------+ |
29 * | +------------+ |
30 * |<--->| MSWC |<--->|
31 * | +------------+ |
32 * | +------------+ |
33 * | | Core | |
34 * |<--->| to Host |<--->|
35 * | | Access | |
36 * | +------------+ |
37 * HMIB | Core Bus
38 * (Host Modules Internal Bus) +------------
39 *
40 *
41 * For most of them, the Host can configure these modules via eSPI(Peripheral
42 * Channel)/LPC by accessing 'Configuration and Control register Set' which IO
43 * base address is 0x4E as default. (The table below illustrates structure of
44 * 'Configuration and Control Register Set') And the interrupts in core domain
45 * help handling any events from host side.
46 *
47 * Index | Configuration and Control Register Set
48 * --------|--------------------------------------------------+ Bank Select
49 * 07h | Logical Device Number Register (LDN) |---------+
50 * --------|--------------------------------------------------- |
51 * 20-2Fh | SuperI/O Configuration Registers | |
52 * ------------------------------------------------------------ |
53 * --------|---------------------------------------------------_ |
54 * 30h | Logical Device Control Register | |_ |
55 * --------|--------------------------------------------------- | |_ |
56 * 60-63h | I/O Space Configuration Registers | | | | |
57 * --------|--------------------------------------------------- | | | |
58 * 70-71h | Interrupt Configuration Registers | | | | |
59 * --------|--------------------------------------------------- | | | |
60 * 73-74h | DMA Configuration Registers (No support in NPCX) | | | | |
61 * --------|--------------------------------------------------- | | |<--+
62 * F0-FFh | Special Logical Device Configuration Registers | | | |
63 * --------|--------------------------------------------------- | | |
64 * |--------------------------------------------------- | |
65 * |--------------------------------------------------- |
66 * |---------------------------------------------------
67 *
68 *
69 * This driver introduces six host sub-modules. It includes:
70 *
71 * 1. Keyboard and Mouse Controller (KBC) interface.
72 * ● Intel 8051SL-compatible Host interface
73 * — 8042 KBD standard interface (ports 60h, 64h)
74 * — Legacy IRQ: IRQ1 (KBD) and IRQ12 (mouse) support
75 * ● Configured by two logical devices: Keyboard and Mouse (LDN 0x06/0x05)
76 *
77 * 2. Power Management (PM) channels.
78 * ● PM channel registers
79 * — Command/Status register
80 * — Data register
81 * channel 1: legacy 62h, 66h; channel 2: legacy 68h, 6Ch;
82 * channel 3: legacy 6Ah, 6Eh; channel 4: legacy 6Bh, 6Fh;
83 * ● PM interrupt using:
84 * — Serial IRQ
85 * — SMI
86 * — EC_SCI
87 * ● Configured by four logical devices: PM1/2/3/4 (LDN 0x11/0x12/0x17/0x1E)
88 *
89 * 3. Shared Memory mechanism (SHM).
90 * This module allows sharing of the on-chip RAM by both Core and the Host.
91 * It also supports the following features:
92 * ● Four Core/Host communication windows for direct RAM access
93 * ● Eight Protection regions for each access window
94 * ● Host IRQ and SMI generation
95 * ● Port 80 debug support
96 * ● Configured by one logical device: SHM (LDN 0x0F)
97 *
98 * 4. Core Access to Host Modules (C2H).
99 * ● A interface to access module registers in host domain.
100 * It enables the Core to access the registers in host domain (i.e., Host
101 * Configuration, Serial Port, SHM, and MSWC), through HMIB.
102 *
103 * 5. Mobile System Wake-Up functions (MSWC).
104 * It detects and handles wake-up events from various sources in the Host
105 * modules and alerts the Core for better power consumption.
106 *
107 * 6. Serial Port (Legacy UART)
108 * It provides UART functionality by supporting serial data communication
109 * with a remote peripheral device or a modem.
110 *
111 * INCLUDE FILES: soc_host.h
112 *
113 */
114
115 #include <assert.h>
116 #include <zephyr/drivers/espi.h>
117 #include <zephyr/drivers/gpio.h>
118 #include <zephyr/drivers/clock_control.h>
119 #include <zephyr/drivers/pinctrl.h>
120 #include <zephyr/kernel.h>
121 #include <zephyr/sys/ring_buffer.h>
122 #include <soc.h>
123 #include "espi_utils.h"
124 #include "soc_host.h"
125 #include "soc_espi.h"
126 #include "soc_miwu.h"
127
128 #include <zephyr/logging/log.h>
129 #include <zephyr/irq.h>
130 LOG_MODULE_REGISTER(host_sub_npcx, LOG_LEVEL_ERR);
131
132 struct host_sub_npcx_config {
133 /* host module instances */
134 struct mswc_reg *const inst_mswc;
135 struct shm_reg *const inst_shm;
136 struct c2h_reg *const inst_c2h;
137 struct kbc_reg *const inst_kbc;
138 struct pmch_reg *const inst_pm_acpi;
139 struct pmch_reg *const inst_pm_hcmd;
140 /* clock configuration */
141 const uint8_t clks_size;
142 const struct npcx_clk_cfg *clks_list;
143 /* mapping table between host access signals and wake-up input */
144 struct npcx_wui host_acc_wui;
145 };
146
147 struct host_sub_npcx_data {
148 sys_slist_t *callbacks; /* pointer on the espi callback list */
149 uint8_t plt_rst_asserted; /* current PLT_RST# status */
150 uint8_t espi_rst_level; /* current ESPI_RST# status */
151 const struct device *host_bus_dev; /* device for eSPI/LPC bus */
152 #ifdef CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE
153 struct ring_buf port80_ring_buf;
154 uint8_t port80_data[CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_RING_BUF_SIZE];
155 struct k_work work;
156 #endif
157 };
158
159 struct npcx_dp80_buf {
160 union {
161 uint16_t offset_code_16;
162 uint8_t offset_code[2];
163 };
164 };
165
166 static const struct npcx_clk_cfg host_dev_clk_cfg[] =
167 NPCX_DT_CLK_CFG_ITEMS_LIST(0);
168
169 struct host_sub_npcx_config host_sub_cfg = {
170 .inst_mswc = (struct mswc_reg *)DT_INST_REG_ADDR_BY_NAME(0, mswc),
171 .inst_shm = (struct shm_reg *)DT_INST_REG_ADDR_BY_NAME(0, shm),
172 .inst_c2h = (struct c2h_reg *)DT_INST_REG_ADDR_BY_NAME(0, c2h),
173 .inst_kbc = (struct kbc_reg *)DT_INST_REG_ADDR_BY_NAME(0, kbc),
174 .inst_pm_acpi = (struct pmch_reg *)DT_INST_REG_ADDR_BY_NAME(0, pm_acpi),
175 .inst_pm_hcmd = (struct pmch_reg *)DT_INST_REG_ADDR_BY_NAME(0, pm_hcmd),
176 .host_acc_wui = NPCX_DT_WUI_ITEM_BY_NAME(0, host_acc_wui),
177 .clks_size = ARRAY_SIZE(host_dev_clk_cfg),
178 .clks_list = host_dev_clk_cfg,
179 };
180
181 struct host_sub_npcx_data host_sub_data;
182
183 /* Application shouldn't touch these flags in KBC status register directly */
184 #define NPCX_KBC_STS_MASK (BIT(NPCX_HIKMST_IBF) | BIT(NPCX_HIKMST_OBF) \
185 | BIT(NPCX_HIKMST_A2))
186
187 /* IO base address of EC Logical Device Configuration */
188 #define NPCX_EC_CFG_IO_ADDR 0x4E
189
190 /* Timeout to wait for Core-to-Host transaction to be completed. */
191 #define NPCX_C2H_TRANSACTION_TIMEOUT_US 200
192
193 /* Logical Device Number Assignments */
194 #define EC_CFG_LDN_MOUSE 0x05
195 #define EC_CFG_LDN_KBC 0x06
196 #define EC_CFG_LDN_SHM 0x0F
197 #define EC_CFG_LDN_ACPI 0x11 /* PM Channel 1 */
198 #define EC_CFG_LDN_HCMD 0x12 /* PM Channel 2 */
199
200 /* Index of EC (4E/4F) Configuration Register */
201 #define EC_CFG_IDX_LDN 0x07
202 #define EC_CFG_IDX_CTRL 0x30
203 #define EC_CFG_IDX_CMD_IO_ADDR_H 0x60
204 #define EC_CFG_IDX_CMD_IO_ADDR_L 0x61
205 #define EC_CFG_IDX_DATA_IO_ADDR_H 0x62
206 #define EC_CFG_IDX_DATA_IO_ADDR_L 0x63
207
208 /* Index of Special Logical Device Configuration (Shared Memory Module) */
209 #define EC_CFG_IDX_SHM_CFG 0xF1
210 #define EC_CFG_IDX_SHM_WND1_ADDR_0 0xF4
211 #define EC_CFG_IDX_SHM_WND1_ADDR_1 0xF5
212 #define EC_CFG_IDX_SHM_WND1_ADDR_2 0xF6
213 #define EC_CFG_IDX_SHM_WND1_ADDR_3 0xF7
214 #define EC_CFG_IDX_SHM_WND2_ADDR_0 0xF8
215 #define EC_CFG_IDX_SHM_WND2_ADDR_1 0xF9
216 #define EC_CFG_IDX_SHM_WND2_ADDR_2 0xFA
217 #define EC_CFG_IDX_SHM_WND2_ADDR_3 0xFB
218 #define EC_CFG_IDX_SHM_DP80_ADDR_RANGE 0xFD
219
220 /* Host sub-device local inline functions */
host_shd_mem_wnd_size_sl(uint32_t size)221 static inline uint8_t host_shd_mem_wnd_size_sl(uint32_t size)
222 {
223 /* The minimum supported shared memory region size is 8 bytes */
224 if (size <= 8U) {
225 size = 8U;
226 }
227
228 /* The maximum supported shared memory region size is 4K bytes */
229 if (size >= 4096U) {
230 size = 4096U;
231 }
232
233 /*
234 * If window size is not a power-of-two, it is rounded-up to the next
235 * power-of-two value, and return value corresponds to RWINx_SIZE field.
236 */
237 return (32 - __builtin_clz(size - 1U)) & 0xff;
238 }
239
240 /* Host KBC sub-device local functions */
241 #if defined(CONFIG_ESPI_PERIPHERAL_8042_KBC)
host_kbc_ibf_isr(const void * arg)242 static void host_kbc_ibf_isr(const void *arg)
243 {
244 ARG_UNUSED(arg);
245 struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc;
246 struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION,
247 ESPI_PERIPHERAL_8042_KBC, ESPI_PERIPHERAL_NODATA
248 };
249 struct espi_evt_data_kbc *kbc_evt =
250 (struct espi_evt_data_kbc *)&evt.evt_data;
251
252 /* KBC Input Buffer Full event */
253 kbc_evt->evt = HOST_KBC_EVT_IBF;
254 /* The data in KBC Input Buffer */
255 kbc_evt->data = inst_kbc->HIKMDI;
256 /*
257 * Indicates if the host sent a command or data.
258 * 0 = data
259 * 1 = Command.
260 */
261 kbc_evt->type = IS_BIT_SET(inst_kbc->HIKMST, NPCX_HIKMST_A2);
262
263 LOG_DBG("%s: kbc data 0x%02x", __func__, evt.evt_data);
264 espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev,
265 evt);
266 }
267
host_kbc_obe_isr(const void * arg)268 static void host_kbc_obe_isr(const void *arg)
269 {
270 ARG_UNUSED(arg);
271 struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc;
272 struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION,
273 ESPI_PERIPHERAL_8042_KBC, ESPI_PERIPHERAL_NODATA
274 };
275 struct espi_evt_data_kbc *kbc_evt =
276 (struct espi_evt_data_kbc *)&evt.evt_data;
277
278 /* Disable KBC OBE interrupt first */
279 inst_kbc->HICTRL &= ~BIT(NPCX_HICTRL_OBECIE);
280
281 LOG_DBG("%s: kbc status 0x%02x", __func__, inst_kbc->HIKMST);
282
283 /*
284 * Notify application that host already read out data. The application
285 * might need to clear status register via espi_api_lpc_write_request()
286 * with E8042_CLEAR_FLAG opcode in callback.
287 */
288 kbc_evt->evt = HOST_KBC_EVT_OBE;
289 kbc_evt->data = 0;
290 kbc_evt->type = 0;
291
292 espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev,
293 evt);
294 }
295
host_kbc_init(void)296 static void host_kbc_init(void)
297 {
298 struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc;
299
300 /* Make sure the previous OBF and IRQ has been sent out. */
301 k_busy_wait(4);
302 /* Set FW_OBF to clear OBF flag in both STATUS and HIKMST to 0 */
303 inst_kbc->HICTRL |= BIT(NPCX_HICTRL_FW_OBF);
304 /* Ensure there is no OBF set in this period. */
305 k_busy_wait(4);
306
307 /*
308 * Init KBC with:
309 * 1. Enable Input Buffer Full (IBF) core interrupt for Keyboard/mouse.
310 * 2. Enable Output Buffer Full Mouse(OBFM) SIRQ 12.
311 * 3. Enable Output Buffer Full Keyboard (OBFK) SIRQ 1.
312 */
313 inst_kbc->HICTRL = BIT(NPCX_HICTRL_IBFCIE) | BIT(NPCX_HICTRL_OBFMIE)
314 | BIT(NPCX_HICTRL_OBFKIE);
315
316 /* Configure SIRQ 1/12 type (level + high) */
317 inst_kbc->HIIRQC = 0x00;
318 }
319 #endif
320
321 /* Host ACPI sub-device local functions */
322 #if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO)
host_acpi_process_input_data(uint8_t data)323 static void host_acpi_process_input_data(uint8_t data)
324 {
325 struct pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi;
326 struct espi_event evt = {
327 .evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION,
328 .evt_details = ESPI_PERIPHERAL_HOST_IO,
329 .evt_data = ESPI_PERIPHERAL_NODATA
330 };
331 struct espi_evt_data_acpi *acpi_evt =
332 (struct espi_evt_data_acpi *)&evt.evt_data;
333
334 LOG_DBG("%s: acpi data 0x%02x", __func__, data);
335
336 /*
337 * Indicates if the host sent a command or data.
338 * 0 = data
339 * 1 = Command.
340 */
341 acpi_evt->type = IS_BIT_SET(inst_acpi->HIPMST, NPCX_HIPMST_CMD);
342 acpi_evt->data = data;
343
344 espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev,
345 evt);
346 }
347
host_acpi_init(void)348 static void host_acpi_init(void)
349 {
350 struct pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi;
351
352 /* Use SMI/SCI postive polarity by default */
353 inst_acpi->HIPMCTL &= ~BIT(NPCX_HIPMCTL_SCIPOL);
354 inst_acpi->HIPMIC &= ~BIT(NPCX_HIPMIC_SMIPOL);
355
356 /* Set SMIB/SCIB bits to make sure SMI#/SCI# are driven to high */
357 inst_acpi->HIPMIC |= BIT(NPCX_HIPMIC_SMIB) | BIT(NPCX_HIPMIC_SCIB);
358
359 /*
360 * Allow SMI#/SCI# generated from PM module.
361 * On eSPI bus, we suggest set VW value of SCI#/SMI# directly.
362 */
363 inst_acpi->HIPMIE |= BIT(NPCX_HIPMIE_SCIE);
364 inst_acpi->HIPMIE |= BIT(NPCX_HIPMIE_SMIE);
365
366 /*
367 * Init ACPI PM channel (Host IO) with:
368 * 1. Enable Input-Buffer Full (IBF) core interrupt.
369 * 2. BIT 7 must be 1.
370 */
371 inst_acpi->HIPMCTL |= BIT(7) | BIT(NPCX_HIPMCTL_IBFIE);
372 }
373 #endif
374
375 #if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)
376 /* Host command argument and memory map buffers */
377 static uint8_t shm_host_cmd[CONFIG_ESPI_NPCX_PERIPHERAL_HOST_CMD_PARAM_SIZE]
378 __aligned(8);
379 /* Host command sub-device local functions */
host_hcmd_process_input_data(uint8_t data)380 static void host_hcmd_process_input_data(uint8_t data)
381 {
382 struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION,
383 ESPI_PERIPHERAL_EC_HOST_CMD, ESPI_PERIPHERAL_NODATA
384 };
385
386 evt.evt_data = data;
387 LOG_DBG("%s: host cmd data 0x%02x", __func__, evt.evt_data);
388 espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev,
389 evt);
390 }
391
host_hcmd_init(void)392 static void host_hcmd_init(void)
393 {
394 struct pmch_reg *const inst_hcmd = host_sub_cfg.inst_pm_hcmd;
395 struct shm_reg *const inst_shm = host_sub_cfg.inst_shm;
396 uint32_t win_size = CONFIG_ESPI_NPCX_PERIPHERAL_HOST_CMD_PARAM_SIZE;
397
398 /* Don't stall SHM transactions */
399 inst_shm->SHM_CTL &= ~0x40;
400 /* Disable Window 1 protection */
401 inst_shm->WIN1_WR_PROT = 0;
402 inst_shm->WIN1_RD_PROT = 0;
403
404 /* Configure Win1 size for ec host command. */
405 SET_FIELD(inst_shm->WIN_SIZE, NPCX_WIN_SIZE_RWIN1_SIZE_FIELD,
406 host_shd_mem_wnd_size_sl(win_size));
407 inst_shm->WIN_BASE1 = (uint32_t)shm_host_cmd;
408
409 /*
410 * Clear processing flag before enabling host's interrupts in case
411 * it's set by the other command during sysjump.
412 */
413 inst_hcmd->HIPMST &= ~BIT(NPCX_HIPMST_F0);
414
415 /*
416 * Init Host Command PM channel (Host IO) with:
417 * 1. Enable Input-Buffer Full (IBF) core interrupt.
418 * 2. BIT 7 must be 1.
419 */
420 inst_hcmd->HIPMCTL |= BIT(7) | BIT(NPCX_HIPMCTL_IBFIE);
421 }
422 #endif
423
424 #if defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)
425 /* Host command argument and memory map buffers */
426 static uint8_t shm_acpi_mmap[CONFIG_ESPI_NPCX_PERIPHERAL_ACPI_SHD_MEM_SIZE]
427 __aligned(8);
host_shared_mem_region_init(void)428 static void host_shared_mem_region_init(void)
429 {
430 struct shm_reg *const inst_shm = host_sub_cfg.inst_shm;
431 uint32_t win_size = CONFIG_ESPI_NPCX_PERIPHERAL_ACPI_SHD_MEM_SIZE;
432
433 /* Don't stall SHM transactions */
434 inst_shm->SHM_CTL &= ~0x40;
435 /* Disable Window 2 protection */
436 inst_shm->WIN2_WR_PROT = 0;
437 inst_shm->WIN2_RD_PROT = 0;
438
439 /* Configure Win2 size for ACPI shared mem region. */
440 SET_FIELD(inst_shm->WIN_SIZE, NPCX_WIN_SIZE_RWIN2_SIZE_FIELD,
441 host_shd_mem_wnd_size_sl(win_size));
442 inst_shm->WIN_BASE2 = (uint32_t)shm_acpi_mmap;
443 /* Enable write protect of Share memory window 2 */
444 inst_shm->WIN2_WR_PROT = 0xFF;
445
446 /*
447 * TODO: Initialize shm_acpi_mmap buffer for host command flags. We
448 * might use EACPI_GET_SHARED_MEMORY in espi_api_lpc_read_request()
449 * instead of setting host command flags here directly.
450 */
451 }
452 #endif
453
454 #if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO) || \
455 defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)
456 /* Host pm (host io) sub-module isr function for all channels such as ACPI. */
host_pmch_ibf_isr(const void * arg)457 static void host_pmch_ibf_isr(const void *arg)
458 {
459 ARG_UNUSED(arg);
460 struct pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi;
461 struct pmch_reg *const inst_hcmd = host_sub_cfg.inst_pm_hcmd;
462 uint8_t in_data;
463
464 /* Host put data on input buffer of ACPI channel */
465 if (IS_BIT_SET(inst_acpi->HIPMST, NPCX_HIPMST_IBF)) {
466 /* Set processing flag before reading command byte */
467 inst_acpi->HIPMST |= BIT(NPCX_HIPMST_F0);
468 /* Read out input data and clear IBF pending bit */
469 in_data = inst_acpi->HIPMDI;
470 #if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO)
471 host_acpi_process_input_data(in_data);
472 #endif
473 }
474
475 /* Host put data on input buffer of HOSTCMD channel */
476 if (IS_BIT_SET(inst_hcmd->HIPMST, NPCX_HIPMST_IBF)) {
477 /* Set processing flag before reading command byte */
478 inst_hcmd->HIPMST |= BIT(NPCX_HIPMST_F0);
479 /* Read out input data and clear IBF pending bit */
480 in_data = inst_hcmd->HIPMDI;
481 #if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)
482 host_hcmd_process_input_data(in_data);
483 #endif
484 }
485 }
486 #endif
487
488 /* Host port80 sub-device local functions */
489 #if defined(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80)
490 #if defined(CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE)
host_port80_work_handler(struct k_work * item)491 static void host_port80_work_handler(struct k_work *item)
492 {
493 uint32_t code = 0;
494 struct host_sub_npcx_data *data = CONTAINER_OF(item, struct host_sub_npcx_data, work);
495 struct ring_buf *rbuf = &data->port80_ring_buf;
496 struct espi_event evt = {ESPI_BUS_PERIPHERAL_NOTIFICATION,
497 (ESPI_PERIPHERAL_INDEX_0 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80,
498 ESPI_PERIPHERAL_NODATA};
499
500 while (!ring_buf_is_empty(rbuf)) {
501 struct npcx_dp80_buf dp80_buf;
502 uint8_t offset;
503
504 ring_buf_get(rbuf, &dp80_buf.offset_code[0], sizeof(dp80_buf.offset_code));
505 offset = dp80_buf.offset_code[1];
506 code |= dp80_buf.offset_code[0] << (8 * offset);
507 if (ring_buf_is_empty(rbuf)) {
508 evt.evt_data = code;
509 espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev,
510 evt);
511 break;
512 }
513 /* peek the offset of the next byte */
514 ring_buf_peek(rbuf, &dp80_buf.offset_code[0], sizeof(dp80_buf.offset_code));
515 offset = dp80_buf.offset_code[1];
516 /*
517 * If the peeked next byte's offset is 0, it is the start of the new code.
518 * Pass the current code to the application layer to handle the Port80 code.
519 */
520 if (offset == 0) {
521 evt.evt_data = code;
522 espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev,
523 evt);
524 code = 0;
525 }
526 }
527 }
528 #endif
529
host_port80_isr(const void * arg)530 static void host_port80_isr(const void *arg)
531 {
532 ARG_UNUSED(arg);
533 struct shm_reg *const inst_shm = host_sub_cfg.inst_shm;
534 uint8_t status = inst_shm->DP80STS;
535
536 #ifdef CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE
537 struct ring_buf *rbuf = &host_sub_data.port80_ring_buf;
538
539 while (IS_BIT_SET(inst_shm->DP80STS, NPCX_DP80STS_FNE)) {
540 struct npcx_dp80_buf dp80_buf;
541
542 dp80_buf.offset_code_16 = inst_shm->DP80BUF;
543 ring_buf_put(rbuf, &dp80_buf.offset_code[0], sizeof(dp80_buf.offset_code));
544 }
545 k_work_submit(&host_sub_data.work);
546 #else
547 struct espi_event evt = {ESPI_BUS_PERIPHERAL_NOTIFICATION,
548 (ESPI_PERIPHERAL_INDEX_0 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80,
549 ESPI_PERIPHERAL_NODATA};
550
551 /* Read out port80 data continuously if FIFO is not empty */
552 while (IS_BIT_SET(inst_shm->DP80STS, NPCX_DP80STS_FNE)) {
553 LOG_DBG("p80: %04x", inst_shm->DP80BUF);
554 evt.evt_data = inst_shm->DP80BUF;
555 espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev, evt);
556 }
557 #endif
558 LOG_DBG("%s: p80 status 0x%02X", __func__, status);
559
560 /* If FIFO is overflow, show error msg */
561 if (IS_BIT_SET(status, NPCX_DP80STS_FOR)) {
562 inst_shm->DP80STS |= BIT(NPCX_DP80STS_FOR);
563 LOG_DBG("Port80 FIFO Overflow!");
564 }
565
566 /* If there are pending post codes remains in FIFO after processing and sending previous
567 * post codes, do not clear the FNE bit. This allows this handler to be called again
568 * immediately after it exists.
569 */
570 if (!IS_BIT_SET(inst_shm->DP80STS, NPCX_DP80STS_FNE)) {
571 /* Clear all pending bit indicates that FIFO was written by host */
572 inst_shm->DP80STS |= BIT(NPCX_DP80STS_FWR);
573 }
574 }
575
host_port80_init(void)576 static void host_port80_init(void)
577 {
578 struct shm_reg *const inst_shm = host_sub_cfg.inst_shm;
579
580 /*
581 * Init PORT80 which includes:
582 * Enables a Core interrupt on every Host write to the FIFO,
583 * SYNC mode (It must be 1 in eSPI mode), Read Auto Advance mode, and
584 * Port80 module itself.
585 */
586 inst_shm->DP80CTL = BIT(NPCX_DP80CTL_CIEN) | BIT(NPCX_DP80CTL_RAA)
587 | BIT(NPCX_DP80CTL_DP80EN) | BIT(NPCX_DP80CTL_SYNCEN);
588 }
589 #endif
590
591 #if defined(CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE)
host_cus_opcode_enable_interrupts(void)592 static void host_cus_opcode_enable_interrupts(void)
593 {
594 /* Enable host KBC sub-device interrupt */
595 if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_8042_KBC)) {
596 irq_enable(DT_INST_IRQ_BY_NAME(0, kbc_ibf, irq));
597 irq_enable(DT_INST_IRQ_BY_NAME(0, kbc_obe, irq));
598 }
599
600 /* Enable host PM channel (Host IO) sub-device interrupt */
601 if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO) ||
602 IS_ENABLED(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)) {
603 irq_enable(DT_INST_IRQ_BY_NAME(0, pmch_ibf, irq));
604 }
605
606 /* Enable host Port80 sub-device interrupt installation */
607 if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80)) {
608 irq_enable(DT_INST_IRQ_BY_NAME(0, p80_fifo, irq));
609 }
610
611 /* Enable host interface interrupts if its interface is eSPI */
612 if (IS_ENABLED(CONFIG_ESPI)) {
613 npcx_espi_enable_interrupts(host_sub_data.host_bus_dev);
614 }
615 }
616
host_cus_opcode_disable_interrupts(void)617 static void host_cus_opcode_disable_interrupts(void)
618 {
619 /* Disable host KBC sub-device interrupt */
620 if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_8042_KBC)) {
621 irq_disable(DT_INST_IRQ_BY_NAME(0, kbc_ibf, irq));
622 irq_disable(DT_INST_IRQ_BY_NAME(0, kbc_obe, irq));
623 }
624
625 /* Disable host PM channel (Host IO) sub-device interrupt */
626 if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO) ||
627 IS_ENABLED(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)) {
628 irq_disable(DT_INST_IRQ_BY_NAME(0, pmch_ibf, irq));
629 }
630
631 /* Disable host Port80 sub-device interrupt installation */
632 if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80)) {
633 irq_disable(DT_INST_IRQ_BY_NAME(0, p80_fifo, irq));
634 }
635
636 /* Disable host interface interrupts if its interface is eSPI */
637 if (IS_ENABLED(CONFIG_ESPI)) {
638 npcx_espi_disable_interrupts(host_sub_data.host_bus_dev);
639 }
640 }
641 #endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */
642
643 #if defined(CONFIG_ESPI_PERIPHERAL_UART)
644 /* host uart pinmux configuration */
645 PINCTRL_DT_DEFINE(DT_INST(0, nuvoton_npcx_host_uart));
646 BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(nuvoton_npcx_host_uart) == 1,
647 "only one 'nuvoton_npcx_host_uart' compatible node may be present");
648 const struct pinctrl_dev_config *huart_cfg =
649 PINCTRL_DT_DEV_CONFIG_GET(DT_INST(0, nuvoton_npcx_host_uart));
650 /* Host UART sub-device local functions */
host_uart_init(void)651 void host_uart_init(void)
652 {
653 struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h;
654
655 /* Configure pin-mux for serial port device */
656 pinctrl_apply_state(huart_cfg, PINCTRL_STATE_DEFAULT);
657
658 /* Make sure unlock host access of serial port */
659 inst_c2h->LKSIOHA &= ~BIT(NPCX_LKSIOHA_LKSPHA);
660 /* Clear 'Host lock violation occurred' bit of serial port initially */
661 inst_c2h->SIOLV |= BIT(NPCX_SIOLV_SPLV);
662 }
663 #endif
664
665 /* host core-to-host interface local functions */
host_c2h_wait_write_done(void)666 static void host_c2h_wait_write_done(void)
667 {
668 struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h;
669 uint32_t elapsed_cycles;
670 uint32_t start_cycles = k_cycle_get_32();
671 uint32_t max_wait_cycles =
672 k_us_to_cyc_ceil32(NPCX_C2H_TRANSACTION_TIMEOUT_US);
673
674 while (IS_BIT_SET(inst_c2h->SIBCTRL, NPCX_SIBCTRL_CSWR)) {
675 elapsed_cycles = k_cycle_get_32() - start_cycles;
676 if (elapsed_cycles > max_wait_cycles) {
677 LOG_ERR("c2h write transaction expired!");
678 break;
679 }
680 }
681 }
682
host_c2h_wait_read_done(void)683 static void host_c2h_wait_read_done(void)
684 {
685 struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h;
686 uint32_t elapsed_cycles;
687 uint32_t start_cycles = k_cycle_get_32();
688 uint32_t max_wait_cycles =
689 k_us_to_cyc_ceil32(NPCX_C2H_TRANSACTION_TIMEOUT_US);
690
691 while (IS_BIT_SET(inst_c2h->SIBCTRL, NPCX_SIBCTRL_CSRD)) {
692 elapsed_cycles = k_cycle_get_32() - start_cycles;
693 if (elapsed_cycles > max_wait_cycles) {
694 LOG_ERR("c2h read transaction expired!");
695 break;
696 }
697 }
698 }
699
host_c2h_write_io_cfg_reg(uint8_t reg_index,uint8_t reg_data)700 void host_c2h_write_io_cfg_reg(uint8_t reg_index, uint8_t reg_data)
701 {
702 struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h;
703
704 /* Disable interrupts */
705 unsigned int key = irq_lock();
706
707 /* Lock host access EC configuration registers (0x4E/0x4F) */
708 inst_c2h->LKSIOHA |= BIT(NPCX_LKSIOHA_LKCFG);
709 /* Enable Core-to-Host access CFG module */
710 inst_c2h->CRSMAE |= BIT(NPCX_CRSMAE_CFGAE);
711
712 /* Verify core-to-host modules is not in progress */
713 host_c2h_wait_read_done();
714 host_c2h_wait_write_done();
715
716 /*
717 * Specifying the in-direct IO address which A0 = 0 indicates the index
718 * register is accessed. Then write index address directly and it starts
719 * a write transaction to host sub-module on LPC/eSPI bus.
720 */
721 inst_c2h->IHIOA = NPCX_EC_CFG_IO_ADDR;
722 inst_c2h->IHD = reg_index;
723 host_c2h_wait_write_done();
724
725 /*
726 * Specifying the in-direct IO address which A0 = 1 indicates the data
727 * register is accessed. Then write data directly and it starts a write
728 * transaction to host sub-module on LPC/eSPI bus.
729 */
730 inst_c2h->IHIOA = NPCX_EC_CFG_IO_ADDR + 1;
731 inst_c2h->IHD = reg_data;
732 host_c2h_wait_write_done();
733
734 /* Disable Core-to-Host access CFG module */
735 inst_c2h->CRSMAE &= ~BIT(NPCX_CRSMAE_CFGAE);
736 /* Unlock host access EC configuration registers (0x4E/0x4F) */
737 inst_c2h->LKSIOHA &= ~BIT(NPCX_LKSIOHA_LKCFG);
738
739 /* Enable interrupts */
740 irq_unlock(key);
741 }
742
host_c2h_read_io_cfg_reg(uint8_t reg_index)743 uint8_t host_c2h_read_io_cfg_reg(uint8_t reg_index)
744 {
745 struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h;
746 uint8_t data_val;
747
748 /* Disable interrupts */
749 unsigned int key = irq_lock();
750
751 /* Lock host access EC configuration registers (0x4E/0x4F) */
752 inst_c2h->LKSIOHA |= BIT(NPCX_LKSIOHA_LKCFG);
753 /* Enable Core-to-Host access CFG module */
754 inst_c2h->CRSMAE |= BIT(NPCX_CRSMAE_CFGAE);
755
756 /* Verify core-to-host modules is not in progress */
757 host_c2h_wait_read_done();
758 host_c2h_wait_write_done();
759
760 /*
761 * Specifying the in-direct IO address which A0 = 0 indicates the index
762 * register is accessed. Then write index address directly and it starts
763 * a write transaction to host sub-module on LPC/eSPI bus.
764 */
765 inst_c2h->IHIOA = NPCX_EC_CFG_IO_ADDR;
766 inst_c2h->IHD = reg_index;
767 host_c2h_wait_write_done();
768
769 /*
770 * Specifying the in-direct IO address which A0 = 1 indicates the data
771 * register is accessed. Then write CSRD bit in SIBCTRL to issue a read
772 * transaction to host sub-module on LPC/eSPI bus. Once it was done,
773 * read data out from IHD.
774 */
775 inst_c2h->IHIOA = NPCX_EC_CFG_IO_ADDR + 1;
776 inst_c2h->SIBCTRL |= BIT(NPCX_SIBCTRL_CSRD);
777 host_c2h_wait_read_done();
778 data_val = inst_c2h->IHD;
779
780 /* Disable Core-to-Host access CFG module */
781 inst_c2h->CRSMAE &= ~BIT(NPCX_CRSMAE_CFGAE);
782 /* Unlock host access EC configuration registers (0x4E/0x4F) */
783 inst_c2h->LKSIOHA &= ~BIT(NPCX_LKSIOHA_LKCFG);
784
785 /* Enable interrupts */
786 irq_unlock(key);
787
788 return data_val;
789 }
790
791 /* Platform specific host sub modules functions */
npcx_host_periph_read_request(enum lpc_peripheral_opcode op,uint32_t * data)792 int npcx_host_periph_read_request(enum lpc_peripheral_opcode op,
793 uint32_t *data)
794 {
795 if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) {
796 struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc;
797
798 /* Make sure kbc 8042 is on */
799 if (!IS_BIT_SET(inst_kbc->HICTRL, NPCX_HICTRL_OBFKIE) ||
800 !IS_BIT_SET(inst_kbc->HICTRL, NPCX_HICTRL_OBFMIE)) {
801 return -ENOTSUP;
802 }
803
804 switch (op) {
805 case E8042_OBF_HAS_CHAR:
806 /* EC has written data back to host. OBF is
807 * automatically cleared after host reads
808 * the data
809 */
810 *data = IS_BIT_SET(inst_kbc->HIKMST, NPCX_HIKMST_OBF);
811 break;
812 case E8042_IBF_HAS_CHAR:
813 *data = IS_BIT_SET(inst_kbc->HIKMST, NPCX_HIKMST_IBF);
814 break;
815 case E8042_READ_KB_STS:
816 *data = inst_kbc->HIKMST;
817 break;
818 default:
819 return -EINVAL;
820 }
821 } else if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) {
822 struct pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi;
823
824 /* Make sure pm channel for apci is on */
825 if (!IS_BIT_SET(inst_acpi->HIPMCTL, NPCX_HIPMCTL_IBFIE)) {
826 return -ENOTSUP;
827 }
828
829 switch (op) {
830 case EACPI_OBF_HAS_CHAR:
831 /* EC has written data back to host. OBF is
832 * automatically cleared after host reads
833 * the data
834 */
835 *data = IS_BIT_SET(inst_acpi->HIPMST, NPCX_HIPMST_OBF);
836 break;
837 case EACPI_IBF_HAS_CHAR:
838 *data = IS_BIT_SET(inst_acpi->HIPMST, NPCX_HIPMST_IBF);
839 break;
840 case EACPI_READ_STS:
841 *data = inst_acpi->HIPMST;
842 break;
843 #if defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)
844 case EACPI_GET_SHARED_MEMORY:
845 *data = (uint32_t)shm_acpi_mmap;
846 break;
847 #endif /* CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION */
848 default:
849 return -EINVAL;
850 }
851 }
852 #if defined(CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE)
853 else if (op >= ECUSTOM_START_OPCODE && op <= ECUSTOM_MAX_OPCODE) {
854 /* Other customized op codes */
855 switch (op) {
856 case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY:
857 *data = (uint32_t)shm_host_cmd;
858 break;
859 case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY_SIZE:
860 *data = CONFIG_ESPI_NPCX_PERIPHERAL_HOST_CMD_PARAM_SIZE;
861 break;
862 default:
863 return -EINVAL;
864 }
865 }
866 #endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */
867 else {
868 return -ENOTSUP;
869 }
870
871 return 0;
872 }
873
npcx_host_periph_write_request(enum lpc_peripheral_opcode op,const uint32_t * data)874 int npcx_host_periph_write_request(enum lpc_peripheral_opcode op,
875 const uint32_t *data)
876 {
877 volatile uint32_t __attribute__((unused)) dummy;
878 struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc;
879
880 if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) {
881 /* Make sure kbc 8042 is on */
882 if (!IS_BIT_SET(inst_kbc->HICTRL, NPCX_HICTRL_OBFKIE) ||
883 !IS_BIT_SET(inst_kbc->HICTRL, NPCX_HICTRL_OBFMIE)) {
884 return -ENOTSUP;
885 }
886 if (data) {
887 LOG_INF("%s: op 0x%x data %x", __func__, op, *data);
888 } else {
889 LOG_INF("%s: op 0x%x only", __func__, op);
890 }
891
892 switch (op) {
893 case E8042_WRITE_KB_CHAR:
894 inst_kbc->HIKDO = *data & 0xff;
895 /*
896 * Enable KBC OBE interrupt after putting data in
897 * keyboard data register.
898 */
899 inst_kbc->HICTRL |= BIT(NPCX_HICTRL_OBECIE);
900 break;
901 case E8042_WRITE_MB_CHAR:
902 inst_kbc->HIMDO = *data & 0xff;
903 /*
904 * Enable KBC OBE interrupt after putting data in
905 * mouse data register.
906 */
907 inst_kbc->HICTRL |= BIT(NPCX_HICTRL_OBECIE);
908 break;
909 case E8042_RESUME_IRQ:
910 /* Enable KBC IBF interrupt */
911 inst_kbc->HICTRL |= BIT(NPCX_HICTRL_IBFCIE);
912 break;
913 case E8042_PAUSE_IRQ:
914 /* Disable KBC IBF interrupt */
915 inst_kbc->HICTRL &= ~BIT(NPCX_HICTRL_IBFCIE);
916 break;
917 case E8042_CLEAR_OBF:
918 /* Clear OBF flag in both STATUS and HIKMST to 0 */
919 inst_kbc->HICTRL |= BIT(NPCX_HICTRL_FW_OBF);
920 break;
921 case E8042_SET_FLAG:
922 /* FW shouldn't modify these flags directly */
923 inst_kbc->HIKMST |= *data & ~NPCX_KBC_STS_MASK;
924 break;
925 case E8042_CLEAR_FLAG:
926 /* FW shouldn't modify these flags directly */
927 inst_kbc->HIKMST &= ~(*data | NPCX_KBC_STS_MASK);
928 break;
929 default:
930 return -EINVAL;
931 }
932 } else if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) {
933 struct pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi;
934
935 /* Make sure pm channel for apci is on */
936 if (!IS_BIT_SET(inst_acpi->HIPMCTL, NPCX_HIPMCTL_IBFIE)) {
937 return -ENOTSUP;
938 }
939
940 switch (op) {
941 case EACPI_WRITE_CHAR:
942 inst_acpi->HIPMDO = (*data & 0xff);
943 break;
944 case EACPI_WRITE_STS:
945 inst_acpi->HIPMST = (*data & 0xff);
946 break;
947 default:
948 return -EINVAL;
949 }
950 }
951 #if defined(CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE)
952 else if (op >= ECUSTOM_START_OPCODE && op <= ECUSTOM_MAX_OPCODE) {
953 /* Other customized op codes */
954 struct pmch_reg *const inst_hcmd = host_sub_cfg.inst_pm_hcmd;
955
956 switch (op) {
957 case ECUSTOM_HOST_SUBS_INTERRUPT_EN:
958 if (*data != 0) {
959 host_cus_opcode_enable_interrupts();
960 } else {
961 host_cus_opcode_disable_interrupts();
962 }
963 break;
964 case ECUSTOM_HOST_CMD_SEND_RESULT:
965 /*
966 * Write result to the data byte. This sets the TOH
967 * status bit.
968 */
969 inst_hcmd->HIPMDO = (*data & 0xff);
970 /* Clear processing flag */
971 inst_hcmd->HIPMST &= ~BIT(NPCX_HIPMST_F0);
972 break;
973 default:
974 return -EINVAL;
975 }
976 }
977 #endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */
978 else {
979 return -ENOTSUP;
980 }
981
982 return 0;
983 }
984
npcx_host_init_subs_host_domain(void)985 void npcx_host_init_subs_host_domain(void)
986 {
987 struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h;
988
989 /* Enable Core-to-Host access module */
990 inst_c2h->SIBCTRL |= BIT(NPCX_SIBCTRL_CSAE);
991
992 if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_8042_KBC)) {
993 /*
994 * Select Keyboard/Mouse banks which LDN are 0x06/05 and enable
995 * modules by setting bit 0 in its Control (index is 0x30) reg.
996 */
997 host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_KBC);
998 host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01);
999
1000 host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_MOUSE);
1001 host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01);
1002 }
1003
1004 if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO)) {
1005 /*
1006 * Select ACPI bank which LDN are 0x11 (PM Channel 1) and enable
1007 * module by setting bit 0 in its Control (index is 0x30) reg.
1008 */
1009 host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_ACPI);
1010 host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01);
1011 }
1012
1013 if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) ||
1014 IS_ENABLED(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)) {
1015 /* Select 'Host Command' bank which LDN are 0x12 (PM chan 2) */
1016 host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_HCMD);
1017 #if defined(CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM)
1018 /* Configure IO address of CMD portt (default: 0x200) */
1019 host_c2h_write_io_cfg_reg(EC_CFG_IDX_CMD_IO_ADDR_H,
1020 (CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM >> 8) & 0xff);
1021 host_c2h_write_io_cfg_reg(EC_CFG_IDX_CMD_IO_ADDR_L,
1022 CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM & 0xff);
1023 /* Configure IO address of Data portt (default: 0x204) */
1024 host_c2h_write_io_cfg_reg(EC_CFG_IDX_DATA_IO_ADDR_H,
1025 ((CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM + 4) >> 8)
1026 & 0xff);
1027 host_c2h_write_io_cfg_reg(EC_CFG_IDX_DATA_IO_ADDR_L,
1028 (CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM + 4) & 0xff);
1029 #endif
1030 /* Enable 'Host Command' io port (PM Channel 2) */
1031 host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01);
1032
1033 /* Select 'Shared Memory' bank which LDN are 0x0F */
1034 host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_SHM);
1035 /* WIN 1 & 2 mapping to IO space */
1036 host_c2h_write_io_cfg_reg(0xF1,
1037 host_c2h_read_io_cfg_reg(0xF1) | 0x30);
1038 /* WIN1 as Host Command on the IO address (default: 0x0800) */
1039 #if defined(CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM)
1040 host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND1_ADDR_1,
1041 (CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM >> 8) & 0xff);
1042 host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND1_ADDR_0,
1043 CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM & 0xff);
1044 #endif
1045 /* Set WIN2 as MEMMAP on the configured IO address */
1046 #if defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM)
1047 host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND2_ADDR_1,
1048 (CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM >> 8) & 0xff);
1049 host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND2_ADDR_0,
1050 CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM & 0xff);
1051 #endif
1052 if (IS_ENABLED(CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE)) {
1053 host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_DP80_ADDR_RANGE, 0x0f);
1054 }
1055 /* Enable SHM direct memory access */
1056 host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01);
1057 }
1058 LOG_DBG("Hos sub-modules configurations are done!");
1059 }
1060
npcx_host_enable_access_interrupt(void)1061 void npcx_host_enable_access_interrupt(void)
1062 {
1063 npcx_miwu_irq_get_and_clear_pending(&host_sub_cfg.host_acc_wui);
1064
1065 npcx_miwu_irq_enable(&host_sub_cfg.host_acc_wui);
1066 }
1067
npcx_host_disable_access_interrupt(void)1068 void npcx_host_disable_access_interrupt(void)
1069 {
1070 npcx_miwu_irq_disable(&host_sub_cfg.host_acc_wui);
1071 }
1072
npcx_host_init_subs_core_domain(const struct device * host_bus_dev,sys_slist_t * callbacks)1073 int npcx_host_init_subs_core_domain(const struct device *host_bus_dev,
1074 sys_slist_t *callbacks)
1075 {
1076 struct mswc_reg *const inst_mswc = host_sub_cfg.inst_mswc;
1077 struct shm_reg *const inst_shm = host_sub_cfg.inst_shm;
1078 const struct device *const clk_dev = DEVICE_DT_GET(NPCX_CLK_CTRL_NODE);
1079 int i;
1080 uint8_t shm_sts;
1081
1082 host_sub_data.callbacks = callbacks;
1083 host_sub_data.host_bus_dev = host_bus_dev;
1084
1085 /* Turn on all host necessary sub-module clocks first */
1086 for (i = 0; i < host_sub_cfg.clks_size; i++) {
1087 int ret;
1088
1089 if (!device_is_ready(clk_dev)) {
1090 return -ENODEV;
1091 }
1092
1093 ret = clock_control_on(clk_dev, (clock_control_subsys_t)
1094 &host_sub_cfg.clks_list[i]);
1095 if (ret < 0) {
1096 return ret;
1097 }
1098 }
1099
1100 /* Configure EC legacy configuration IO base address to 0x4E. */
1101 if (!IS_BIT_SET(inst_mswc->MSWCTL1, NPCX_MSWCTL1_VHCFGA)) {
1102 inst_mswc->HCBAL = NPCX_EC_CFG_IO_ADDR;
1103 inst_mswc->HCBAH = 0x0;
1104 }
1105
1106 /*
1107 * Set HOSTWAIT bit and avoid the other settings, then host can freely
1108 * communicate with slave (EC).
1109 */
1110 inst_shm->SMC_CTL &= BIT(NPCX_SMC_CTL_HOSTWAIT);
1111 /* Clear shared memory status */
1112 shm_sts = inst_shm->SMC_STS;
1113 inst_shm->SMC_STS = shm_sts;
1114
1115 /* host sub-module initialization in core domain */
1116 #if defined(CONFIG_ESPI_PERIPHERAL_8042_KBC)
1117 host_kbc_init();
1118 #endif
1119 #if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO)
1120 host_acpi_init();
1121 #endif
1122 #if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)
1123 host_hcmd_init();
1124 #endif
1125 #if defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)
1126 host_shared_mem_region_init();
1127 #endif
1128 #if defined(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80)
1129 host_port80_init();
1130 #if defined(CONFIG_ESPI_NPCX_PERIPHERAL_DEBUG_PORT_80_MULTI_BYTE)
1131 ring_buf_init(&host_sub_data.port80_ring_buf, sizeof(host_sub_data.port80_data),
1132 host_sub_data.port80_data);
1133 k_work_init(&host_sub_data.work, host_port80_work_handler);
1134 #endif
1135 #endif
1136 #if defined(CONFIG_ESPI_PERIPHERAL_UART)
1137 host_uart_init();
1138 #endif
1139
1140 /* Host KBC sub-device interrupt installation */
1141 #if defined(CONFIG_ESPI_PERIPHERAL_8042_KBC)
1142 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, kbc_ibf, irq),
1143 DT_INST_IRQ_BY_NAME(0, kbc_ibf, priority),
1144 host_kbc_ibf_isr,
1145 NULL, 0);
1146
1147 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, kbc_obe, irq),
1148 DT_INST_IRQ_BY_NAME(0, kbc_obe, priority),
1149 host_kbc_obe_isr,
1150 NULL, 0);
1151 #endif
1152
1153 /* Host PM channel (Host IO) sub-device interrupt installation */
1154 #if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO) || \
1155 defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)
1156 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, pmch_ibf, irq),
1157 DT_INST_IRQ_BY_NAME(0, pmch_ibf, priority),
1158 host_pmch_ibf_isr,
1159 NULL, 0);
1160 #endif
1161
1162 /* Host Port80 sub-device interrupt installation */
1163 #if defined(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80)
1164 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, p80_fifo, irq),
1165 DT_INST_IRQ_BY_NAME(0, p80_fifo, priority),
1166 host_port80_isr,
1167 NULL, 0);
1168 #endif
1169
1170 if (IS_ENABLED(CONFIG_PM)) {
1171 /*
1172 * Configure the host access wake-up event triggered from a host
1173 * transaction on eSPI/LPC bus. Do not enable it here. Or plenty
1174 * of interrupts will jam the system in S0.
1175 */
1176 npcx_miwu_interrupt_configure(&host_sub_cfg.host_acc_wui,
1177 NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_HIGH);
1178 }
1179
1180 return 0;
1181 }
1182