Skip to content

Commit da76737

Browse files
JhanBoChao-Realtekkartben
authored andcommitted
driver: espi: add espi peripheral channel 8042_KBC driver for rts5912
add espi peripheral channel 8042_KBC driver for rts5912 Signed-off-by: jhan bo chao <[email protected]>
1 parent 805b213 commit da76737

File tree

3 files changed

+384
-0
lines changed

3 files changed

+384
-0
lines changed

drivers/espi/Kconfig.rts5912

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ config ESPI_RTS5912
1010

1111
if ESPI_RTS5912
1212

13+
config ESPI_PERIPHERAL_8042_KBC
14+
default y
15+
1316
config ESPI_PERIPHERAL_ACPI_SHM_REGION
1417
default y
1518

drivers/espi/espi_realtek_rts5912.c

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ LOG_MODULE_REGISTER(espi, CONFIG_ESPI_LOG_LEVEL);
2020
#include "reg/reg_acpi.h"
2121
#include "reg/reg_emi.h"
2222
#include "reg/reg_espi.h"
23+
#include "reg/reg_kbc.h"
2324
#include "reg/reg_port80.h"
2425

2526
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1, "support only one espi compatible node");
@@ -28,6 +29,11 @@ struct espi_rts5912_config {
2829
volatile struct espi_reg *const espi_reg;
2930
uint32_t espislv_clk_grp;
3031
uint32_t espislv_clk_idx;
32+
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
33+
volatile struct kbc_reg *const kbc_reg;
34+
uint32_t kbc_clk_grp;
35+
uint32_t kbc_clk_idx;
36+
#endif
3137
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
3238
volatile struct acpi_reg *const acpi_reg;
3339
uint32_t acpi_clk_grp;
@@ -58,6 +64,10 @@ struct espi_rts5912_config {
5864
struct espi_rts5912_data {
5965
sys_slist_t callbacks;
6066
uint32_t config_data;
67+
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
68+
int kbc_int_en;
69+
int kbc_pre_irq1;
70+
#endif
6171
#ifdef CONFIG_ESPI_OOB_CHANNEL
6272
struct k_sem oob_rx_lock;
6373
struct k_sem oob_tx_lock;
@@ -71,6 +81,222 @@ struct espi_rts5912_data {
7181
#endif
7282
};
7383

84+
/*
85+
* =========================================================================
86+
* ESPI Peripheral KBC
87+
* =========================================================================
88+
*/
89+
90+
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
91+
92+
static int espi_send_vw_event(uint8_t index, uint8_t data, const struct device *dev);
93+
94+
static void kbc_ibf_isr(const struct device *dev)
95+
{
96+
const struct espi_rts5912_config *const espi_config = dev->config;
97+
struct espi_rts5912_data *espi_data = dev->data;
98+
struct espi_event evt = {
99+
ESPI_BUS_PERIPHERAL_NOTIFICATION,
100+
ESPI_PERIPHERAL_8042_KBC,
101+
ESPI_PERIPHERAL_NODATA,
102+
};
103+
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
104+
struct espi_evt_data_kbc *kbc_evt = (struct espi_evt_data_kbc *)&evt.evt_data;
105+
106+
/*
107+
* Indicates if the host sent a command or data.
108+
* 0 = data
109+
* 1 = Command.
110+
*/
111+
kbc_evt->type = kbc_reg->STS & KBC_STS_CMDSEL ? 1 : 0;
112+
113+
/* The data in KBC Input Buffer */
114+
kbc_evt->data = kbc_reg->IB;
115+
116+
/* KBC Input Buffer Full event */
117+
kbc_evt->evt = HOST_KBC_EVT_IBF;
118+
espi_send_callbacks(&espi_data->callbacks, dev, evt);
119+
}
120+
121+
static void kbc_obe_isr(const struct device *dev)
122+
{
123+
const struct espi_rts5912_config *const espi_config = dev->config;
124+
struct espi_rts5912_data *espi_data = dev->data;
125+
struct espi_event evt = {
126+
ESPI_BUS_PERIPHERAL_NOTIFICATION,
127+
ESPI_PERIPHERAL_8042_KBC,
128+
ESPI_PERIPHERAL_NODATA,
129+
};
130+
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
131+
struct espi_evt_data_kbc *kbc_evt = (struct espi_evt_data_kbc *)&evt.evt_data;
132+
133+
if (espi_data->kbc_pre_irq1 == 1 && !espi_send_vw_event(0x0, 0x01, dev)) {
134+
espi_data->kbc_pre_irq1 = 0;
135+
}
136+
137+
if (kbc_reg->STS & KBC_STS_OBF) {
138+
kbc_reg->OB |= KBC_OB_OBCLR;
139+
}
140+
141+
/* Notify application that host already read out data. */
142+
kbc_evt->type = 0;
143+
kbc_evt->data = 0;
144+
kbc_evt->evt = HOST_KBC_EVT_OBE;
145+
espi_send_callbacks(&espi_data->callbacks, dev, evt);
146+
}
147+
148+
static int espi_kbc_setup(const struct device *dev)
149+
{
150+
const struct espi_rts5912_config *const espi_config = dev->config;
151+
struct espi_rts5912_data *const espi_data = dev->data;
152+
struct rts5912_sccon_subsys sccon;
153+
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
154+
int rc;
155+
156+
if (!device_is_ready(espi_config->clk_dev)) {
157+
LOG_ERR("KBC clock not ready");
158+
return -ENODEV;
159+
}
160+
161+
espi_data->kbc_int_en = 1;
162+
espi_data->kbc_pre_irq1 = 0;
163+
164+
sccon.clk_grp = espi_config->kbc_clk_grp;
165+
sccon.clk_idx = espi_config->kbc_clk_idx;
166+
167+
rc = clock_control_on(espi_config->clk_dev, (clock_control_subsys_t)&sccon);
168+
if (rc != 0) {
169+
LOG_ERR("KBC clock control on failed");
170+
return rc;
171+
}
172+
173+
kbc_reg->VWCTRL1 = (0x01 << KBC_VWCTRL1_IRQNUM_Pos) | KBC_VWCTRL1_ACTEN;
174+
kbc_reg->INTEN = KBC_INTEN_IBFINTEN | KBC_INTEN_OBFINTEN;
175+
176+
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, irq));
177+
NVIC_ClearPendingIRQ(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, irq));
178+
179+
/* IBF */
180+
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, irq),
181+
DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, priority), kbc_ibf_isr,
182+
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
183+
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_ibf, irq));
184+
185+
/* OBE */
186+
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, irq),
187+
DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, priority), kbc_obe_isr,
188+
DEVICE_DT_GET(DT_DRV_INST(0)), 0);
189+
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), kbc_obe, irq));
190+
191+
return 0;
192+
}
193+
194+
static int lpc_request_read_8042(const struct device *dev, enum lpc_peripheral_opcode op,
195+
uint32_t *data)
196+
{
197+
const struct espi_rts5912_config *const espi_config = dev->config;
198+
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
199+
200+
switch (op) {
201+
case E8042_OBF_HAS_CHAR:
202+
*data = (kbc_reg->STS & KBC_STS_OBF) ? 1 : 0;
203+
break;
204+
case E8042_IBF_HAS_CHAR:
205+
*data = (kbc_reg->STS & KBC_STS_IBF) ? 1 : 0;
206+
break;
207+
case E8042_READ_KB_STS:
208+
*data = kbc_reg->STS;
209+
break;
210+
default:
211+
return -EINVAL;
212+
}
213+
214+
return 0;
215+
}
216+
217+
static int espi_send_vw_event(uint8_t index, uint8_t data, const struct device *dev);
218+
219+
static void espi_send_vw_event_with_kbdata(uint8_t index, uint8_t data, uint32_t kbc_data,
220+
const struct device *dev);
221+
222+
static uint8_t kbc_write(uint8_t data, const struct device *dev)
223+
{
224+
const struct espi_rts5912_config *const espi_config = dev->config;
225+
const struct espi_rts5912_data *const espi_data = dev->data;
226+
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
227+
uint32_t exData = (uint32_t)data;
228+
229+
if (espi_data->kbc_pre_irq1 == 1) {
230+
/* Gen IRQ1-Level High to VW ch */
231+
espi_send_vw_event(0x0, 0x01, dev);
232+
}
233+
234+
if (espi_data->kbc_int_en) {
235+
/* Gen IRQ1-Level High to VW ch */
236+
espi_send_vw_event_with_kbdata(0x0, 0x81, exData, dev);
237+
} else {
238+
kbc_reg->OB = exData;
239+
}
240+
241+
return 0;
242+
}
243+
244+
static int lpc_request_write_8042(const struct device *dev, enum lpc_peripheral_opcode op,
245+
uint32_t *data)
246+
{
247+
struct espi_rts5912_data *const espi_data = dev->data;
248+
const struct espi_rts5912_config *const espi_config = dev->config;
249+
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
250+
251+
switch (op) {
252+
case E8042_WRITE_KB_CHAR:
253+
kbc_write(*data & 0xff, dev);
254+
break;
255+
case E8042_WRITE_MB_CHAR:
256+
kbc_write(*data & 0xff, dev);
257+
break;
258+
case E8042_RESUME_IRQ:
259+
espi_data->kbc_int_en = 1;
260+
break;
261+
case E8042_PAUSE_IRQ:
262+
espi_data->kbc_int_en = 0;
263+
break;
264+
case E8042_CLEAR_OBF:
265+
kbc_reg->OB |= KBC_OB_OBCLR;
266+
break;
267+
case E8042_SET_FLAG:
268+
/* FW shouldn't modify these flags directly */
269+
*data &= ~(KBC_STS_OBF | KBC_STS_IBF | KBC_STS_STS2);
270+
kbc_reg->STS |= *data & 0xff;
271+
break;
272+
case E8042_CLEAR_FLAG:
273+
/* FW shouldn't modify these flags directly */
274+
*data |= KBC_STS_OBF | KBC_STS_IBF | KBC_STS_STS2;
275+
kbc_reg->STS &= ~(*data & 0xff);
276+
break;
277+
default:
278+
return -EINVAL;
279+
}
280+
281+
return 0;
282+
}
283+
284+
#else /* CONFIG_ESPI_PERIPHERAL_8042_KBC */
285+
286+
static int lpc_request_read_8042(const struct device *dev, enum lpc_peripheral_opcode op,
287+
uint32_t *data)
288+
{
289+
return -ENOTSUP;
290+
}
291+
292+
static int lpc_request_write_8042(const struct device *dev, enum lpc_peripheral_opcode op,
293+
uint32_t *data)
294+
{
295+
return -ENOTSUP;
296+
}
297+
298+
#endif /* CONFIG_ESPI_PERIPHERAL_8042_KBC */
299+
74300
/*
75301
* =========================================================================
76302
* ESPI Peripheral Shared Memory Region
@@ -1238,6 +1464,81 @@ static void espi_vw_ch_setup(const struct device *dev)
12381464
irq_enable(DT_IRQ_BY_NAME(DT_DRV_INST(0), vw_idx61, irq));
12391465
}
12401466

1467+
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
1468+
1469+
#define ESPI_VW_EVENT_IDLE_TIMEOUT_US 1024UL
1470+
#define ESPI_VW_EVENT_COMPLETE_TIMEOUT_US 10000UL
1471+
1472+
static int espi_send_vw_event(uint8_t index, uint8_t data, const struct device *dev)
1473+
{
1474+
const struct espi_rts5912_config *const espi_config = dev->config;
1475+
uint32_t i;
1476+
1477+
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
1478+
1479+
if ((espi_reg->EVCFG & ESPI_EVCFG_CHEN) == 0 || (espi_reg->EVCFG & ESPI_EVCFG_CHRDY) == 0) {
1480+
return -EBUSY;
1481+
}
1482+
1483+
/* Wait for TX FIFO to not be full before writing, with timeout */
1484+
if (!WAIT_FOR(!(espi_reg->EVSTS & ESPI_EVSTS_TXFULL), ESPI_VW_EVENT_IDLE_TIMEOUT_US,
1485+
k_busy_wait(1))) {
1486+
return -EBUSY;
1487+
}
1488+
1489+
i = 0x0000FFFF & ((uint32_t)index << 8 | (uint32_t)data);
1490+
espi_reg->EVTXDAT = i;
1491+
1492+
/* Wait for TX FIFO to not be full after writing, with shorter timeout */
1493+
if (!WAIT_FOR(!(espi_reg->EVSTS & ESPI_EVSTS_TXFULL), ESPI_VW_EVENT_COMPLETE_TIMEOUT_US,
1494+
NULL)) {
1495+
return -EBUSY;
1496+
}
1497+
1498+
espi_reg->EVSTS |= ESPI_EVSTS_TXDONE;
1499+
1500+
return 0;
1501+
}
1502+
1503+
static void espi_send_vw_event_with_kbdata(uint8_t index, uint8_t data, uint32_t kbc_data,
1504+
const struct device *dev)
1505+
{
1506+
const struct espi_rts5912_config *const espi_config = dev->config;
1507+
struct espi_rts5912_data *const espi_data = dev->data;
1508+
volatile struct espi_reg *const espi_reg = espi_config->espi_reg;
1509+
volatile struct kbc_reg *const kbc_reg = espi_config->kbc_reg;
1510+
uint32_t i;
1511+
1512+
if ((espi_reg->EVCFG & ESPI_EVCFG_CHEN) == 0 || (espi_reg->EVCFG & ESPI_EVCFG_CHRDY) == 0) {
1513+
return;
1514+
}
1515+
1516+
/* Wait for TX FIFO to not be full before writing, with timeout */
1517+
if (!WAIT_FOR(!(espi_reg->EVSTS & ESPI_EVSTS_TXFULL), ESPI_VW_EVENT_COMPLETE_TIMEOUT_US,
1518+
k_busy_wait(1))) {
1519+
return;
1520+
}
1521+
1522+
__disable_irq();
1523+
kbc_reg->OB = kbc_data;
1524+
i = 0x0000FFFF & ((uint32_t)index << 8 | (uint32_t)data);
1525+
espi_reg->EVTXDAT = i;
1526+
1527+
/* Wait for TX FIFO to not be full after writing, in IRQ disabled state */
1528+
if (!WAIT_FOR(!(espi_reg->EVSTS & ESPI_EVSTS_TXFULL), ESPI_VW_EVENT_COMPLETE_TIMEOUT_US,
1529+
k_busy_wait(1))) {
1530+
espi_data->kbc_pre_irq1 = 1;
1531+
__enable_irq();
1532+
return;
1533+
}
1534+
1535+
espi_data->kbc_pre_irq1 = 1;
1536+
espi_reg->EVSTS |= ESPI_EVSTS_TXDONE;
1537+
__enable_irq();
1538+
}
1539+
1540+
#endif /* CONFIG_ESPI_PERIPHERAL_8042_KBC */
1541+
12411542
#endif /* CONFIG_ESPI_VWIRE_CHANNEL */
12421543

12431544
/*
@@ -1883,6 +2184,15 @@ static int espi_rts5912_init(const struct device *dev)
18832184
/* Setup eSPI bus reset */
18842185
espi_bus_reset_setup(dev);
18852186

2187+
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
2188+
/* Setup KBC */
2189+
rc = espi_kbc_setup(dev);
2190+
if (rc != 0) {
2191+
LOG_ERR("eSPI KBC setup failed");
2192+
goto exit;
2193+
}
2194+
#endif
2195+
18862196
#ifdef CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION
18872197
espi_setup_acpi_shm(espi_config);
18882198
#endif
@@ -1950,6 +2260,11 @@ static const struct espi_rts5912_config espi_rts5912_config = {
19502260
.espi_reg = (volatile struct espi_reg *const)DT_INST_REG_ADDR_BY_NAME(0, espi_target),
19512261
.espislv_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), espi_target, clk_grp),
19522262
.espislv_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), espi_target, clk_idx),
2263+
#ifdef CONFIG_ESPI_PERIPHERAL_8042_KBC
2264+
.kbc_reg = (volatile struct kbc_reg *const)DT_INST_REG_ADDR_BY_NAME(0, kbc),
2265+
.kbc_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), kbc, clk_grp),
2266+
.kbc_clk_idx = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), kbc, clk_idx),
2267+
#endif
19532268
#ifdef CONFIG_ESPI_PERIPHERAL_HOST_IO
19542269
.acpi_reg = (volatile struct acpi_reg *const)DT_INST_REG_ADDR_BY_NAME(0, acpi),
19552270
.acpi_clk_grp = DT_CLOCKS_CELL_BY_NAME(DT_DRV_INST(0), acpi, clk_grp),

0 commit comments

Comments
 (0)