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