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