1 /*
2 * Copyright (c) 2020 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <device.h>
8 #include <soc.h>
9 #include <drivers/gpio.h>
10 #include <drivers/espi.h>
11 #include <logging/log_ctrl.h>
12 #include <logging/log.h>
13 #include "espi_oob_handler.h"
14
15 LOG_MODULE_DECLARE(espi, CONFIG_ESPI_LOG_LEVEL);
16
17 struct oob_header {
18 uint8_t dest_slave_addr;
19 uint8_t oob_cmd_code;
20 uint8_t byte_cnt;
21 uint8_t src_slave_addr;
22 };
23
24 #ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
25
26 #define OOB_THREAD_STACK_SIZE 512ul
27 #define OOB_THREAD_PRIORITY K_PRIO_COOP(5)
28 #define OOB_THREAD_WAIT -1
29
30 /* Thread to process asynchronous callbacks */
31 void espihub_thread(void *p1, void *p2, void *p3);
32
33 void temperature_timer(struct k_timer *timer_id);
34
35 K_TIMER_DEFINE(temp_timer, temperature_timer, NULL);
36 K_THREAD_DEFINE(espihub_thrd_id, OOB_THREAD_STACK_SIZE, espihub_thread,
37 NULL, NULL, NULL,
38 OOB_THREAD_PRIORITY, K_INHERIT_PERMS, OOB_THREAD_WAIT);
39
40 K_MSGQ_DEFINE(from_host, sizeof(uint8_t), 8, 4);
41
42 struct thread_context {
43 const struct device *espi_dev;
44 int cycles;
45 };
46
47 static struct thread_context context;
48 static bool need_temp;
49 #endif
50
51 static struct espi_oob_packet resp_pckt;
52 static uint8_t buf[MAX_ESPI_BUF_LEN];
53
request_temp(const struct device * dev)54 static int request_temp(const struct device *dev)
55 {
56 int ret;
57 struct oob_header oob_hdr;
58 struct espi_oob_packet req_pckt;
59
60 LOG_WRN("%s", __func__);
61
62 oob_hdr.dest_slave_addr = PCH_DEST_SLV_ADDR;
63 oob_hdr.oob_cmd_code = OOB_CMDCODE;
64 oob_hdr.byte_cnt = 1;
65 oob_hdr.src_slave_addr = SRC_SLV_ADDR;
66
67 /* Packetize OOB request */
68 req_pckt.buf = (uint8_t *)&oob_hdr;
69 req_pckt.len = sizeof(struct oob_header);
70
71 ret = espi_send_oob(dev, &req_pckt);
72 if (ret) {
73 LOG_ERR("OOB Tx failed %d", ret);
74 return ret;
75 }
76
77 return 0;
78 }
79
retrieve_packet(const struct device * dev,uint8_t * sender)80 static int retrieve_packet(const struct device *dev, uint8_t *sender)
81 {
82 int ret;
83
84 #ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
85 /* Note that no data is in the item */
86 uint8_t response_len;
87
88 if (k_msgq_num_used_get(&from_host) == 0U) {
89 return -EINVAL;
90 }
91
92 k_msgq_get(&from_host, &response_len, K_FOREVER);
93 #endif
94
95 resp_pckt.buf = (uint8_t *)&buf;
96 resp_pckt.len = MAX_ESPI_BUF_LEN;
97
98 ret = espi_receive_oob(dev, &resp_pckt);
99 if (ret) {
100 LOG_ERR("OOB Rx failed %d", ret);
101 return ret;
102 }
103
104 LOG_INF("OOB transaction completed rcvd: %d bytes", resp_pckt.len);
105 for (int i = 0; i < resp_pckt.len; i++) {
106 LOG_INF("%x ", buf[i]);
107 }
108
109 if (sender) {
110 *sender = buf[OOB_RESPONSE_SENDER_INDEX];
111 }
112
113 return 0;
114 }
115
get_pch_temp_sync(const struct device * dev)116 int get_pch_temp_sync(const struct device *dev)
117 {
118 int ret;
119
120 for (int i = 0; i < MIN_GET_TEMP_CYCLES; i++) {
121 ret = request_temp(dev);
122 if (ret) {
123 LOG_ERR("OOB req failed %d", ret);
124 return ret;
125 }
126
127 ret = retrieve_packet(dev, NULL);
128 if (ret) {
129 LOG_ERR("OOB retrieve failed %d", ret);
130 return ret;
131 }
132 }
133
134 return 0;
135 }
136
get_pch_temp_async(const struct device * dev)137 int get_pch_temp_async(const struct device *dev)
138 {
139 #if !defined(CONFIG_ESPI_OOB_CHANNEL) || \
140 !defined(CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC)
141 return -ENOTSUP;
142 #else
143 context.espi_dev = dev;
144 context.cycles = MIN_GET_TEMP_CYCLES;
145
146 k_thread_start(espihub_thrd_id);
147 k_thread_join(espihub_thrd_id, K_FOREVER);
148
149 return 0;
150 #endif
151 }
152
153 #ifdef CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC
154
oob_rx_handler(const struct device * dev,struct espi_callback * cb,struct espi_event event)155 void oob_rx_handler(const struct device *dev, struct espi_callback *cb,
156 struct espi_event event)
157 {
158 uint8_t last_resp_len = event.evt_details;
159
160 LOG_WRN("%s", __func__);
161 /* Post for post-processing in a thread
162 * Should not attempt to retrieve in callback context
163 */
164 k_msgq_put(&from_host, &last_resp_len, K_NO_WAIT);
165 }
166
167
temperature_timer(struct k_timer * timer_id)168 void temperature_timer(struct k_timer *timer_id)
169 {
170 LOG_WRN("%s", __func__);
171 need_temp = true;
172 }
173
espihub_thread(void * p1,void * p2,void * p3)174 void espihub_thread(void *p1, void *p2, void *p3)
175 {
176 int ret;
177 uint8_t temp;
178 uint8_t sender;
179
180 LOG_DBG("%s", __func__);
181 k_timer_start(&temp_timer, K_MSEC(100), K_MSEC(100));
182 while (context.cycles > 0) {
183 k_msleep(50);
184
185 ret = retrieve_packet(context.espi_dev, &sender);
186 if (!ret) {
187 switch (sender) {
188 case PCH_DEST_SLV_ADDR:
189 LOG_INF("PCH response");
190 /* Any other checks */
191 if (resp_pckt.len == OOB_RESPONSE_LEN) {
192 temp = buf[OOB_RESPONSE_DATA_INDEX];
193 LOG_INF("Temp %d", temp);
194 } else {
195 LOG_ERR("Incorrect size response");
196 }
197
198 break;
199 default:
200 LOG_INF("Other host sender %x", sender);
201 }
202 } else {
203 LOG_ERR("Failure to retrieve temp %d", ret);
204 }
205
206 /* Decrease cycles in both cases failure/success */
207 context.cycles--;
208
209 if (need_temp) {
210 request_temp(context.espi_dev);
211 need_temp = false;
212 }
213 }
214
215 k_timer_stop(&temp_timer);
216 }
217 #endif /* CONFIG_ESPI_OOB_CHANNEL_RX_ASYNC */
218