1 /*
2 * Copyright (c) 2025 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 */
7
8 #include "zephyr/drivers/gpio.h"
9 #include "zephyr/pmci/mctp/mctp_i2c_gpio_common.h"
10 #include "zephyr/rtio/rtio.h"
11 #include <zephyr/sys/__assert.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/drivers/uart.h>
14 #include <zephyr/pmci/mctp/mctp_i2c_gpio_controller.h>
15 #include <crc-16-ccitt.h>
16
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(mctp_i2c_gpio_controller, CONFIG_MCTP_LOG_LEVEL);
19
20
21 static void mctp_start_rx(struct mctp_binding_i2c_gpio_controller *b,
22 bool chained_rx);
23
rx_completion(struct rtio * r,const struct rtio_sqe * sqe,void * arg0)24 static void rx_completion(struct rtio *r, const struct rtio_sqe *sqe, void *arg0)
25 {
26 struct mctp_binding_i2c_gpio_controller *b = arg0;
27 struct rtio_cqe *cqe;
28
29 while ((cqe = rtio_cqe_consume(r))) {
30 rtio_cqe_release(r, cqe);
31 }
32
33 struct mctp_pktbuf *pkt = mctp_pktbuf_alloc(&b->binding, b->rx_buf_len);
34
35 memcpy(pkt->data, b->rx_buf, b->rx_buf_len);
36
37 LOG_DBG("giving pkt to mctp, len %d", b->rx_buf_len);
38 mctp_bus_rx(&b->binding, pkt);
39
40 /* Walk our pending bits from the current index, and start the next one if needed */
41 struct mctp_i2c_gpio_controller_cb *cb = b->inflight_rx;
42
43 /* Re-enable the GPIO interrupt */
44 gpio_pin_interrupt_configure_dt(&b->endpoint_gpios[cb->index], GPIO_INT_ENABLE);
45
46 /* Try and start the next transfer if one is pending */
47 mctp_start_rx(b, true);
48 }
49
50
rx_len_completion(struct rtio * r,const struct rtio_sqe * sqe,void * arg0)51 static void rx_len_completion(struct rtio *r, const struct rtio_sqe *sqe, void *arg0)
52 {
53 const uint8_t mctp_tx_msg_addr = MCTP_I2C_GPIO_TX_MSG_ADDR;
54
55 struct mctp_binding_i2c_gpio_controller *b = arg0;
56 const struct rtio_iodev *iodev = b->endpoint_iodevs[b->inflight_rx->index];
57 struct rtio_cqe *cqe;
58
59 while ((cqe = rtio_cqe_consume(r))) {
60 rtio_cqe_release(r, cqe);
61 }
62 struct rtio_sqe *write_msg_addr_sqe = rtio_sqe_acquire(b->r_rx);
63 struct rtio_sqe *read_msg_sqe = rtio_sqe_acquire(b->r_rx);
64 struct rtio_sqe *callback_sqe = rtio_sqe_acquire(b->r_rx);
65
66 LOG_DBG("reading buf %d", b->rx_buf_len);
67 rtio_sqe_prep_tiny_write(write_msg_addr_sqe, iodev, RTIO_PRIO_NORM,
68 &mctp_tx_msg_addr, 1, NULL);
69 write_msg_addr_sqe->flags |= RTIO_SQE_TRANSACTION;
70
71 rtio_sqe_prep_read(read_msg_sqe, iodev, RTIO_PRIO_NORM, b->rx_buf, b->rx_buf_len, NULL);
72 read_msg_sqe->flags |= RTIO_SQE_CHAINED;
73 read_msg_sqe->iodev_flags |= RTIO_IODEV_I2C_RESTART | RTIO_IODEV_I2C_STOP;
74
75 rtio_sqe_prep_callback(callback_sqe, rx_completion, b, NULL);
76 callback_sqe->flags |= RTIO_SQE_NO_RESPONSE;
77
78 rtio_submit(b->r_rx, 0);
79 }
80
81 /*
82 * Atomically start or mark as pending the next receive
83 */
mctp_start_rx(struct mctp_binding_i2c_gpio_controller * b,bool chained_rx)84 static void mctp_start_rx(struct mctp_binding_i2c_gpio_controller *b, bool chained_rx)
85 {
86 /* Critical section to set the next inflight transmit */
87 k_spinlock_key_t key = k_spin_lock(&b->rx_lock);
88
89 /* Ongoing transfer already in fight */
90 if (!chained_rx && b->inflight_rx != NULL) {
91 k_spin_unlock(&b->rx_lock, key);
92 return;
93 }
94
95 struct mpsc_node *node = mpsc_pop(&b->rx_q);
96
97 if (node == NULL) {
98 b->inflight_rx = NULL;
99 k_spin_unlock(&b->rx_lock, key);
100 return;
101 }
102
103 struct mctp_i2c_gpio_controller_cb *next =
104 CONTAINER_OF(node, struct mctp_i2c_gpio_controller_cb, q);
105
106 b->inflight_rx = next;
107 k_spin_unlock(&b->rx_lock, key);
108
109 const uint8_t mctp_tx_msg_len_addr = MCTP_I2C_GPIO_TX_MSG_LEN_ADDR;
110 const struct rtio_iodev *iodev = b->endpoint_iodevs[next->index];
111 struct rtio_sqe *write_len_addr_sqe = rtio_sqe_acquire(b->r_rx);
112 struct rtio_sqe *read_len_sqe = rtio_sqe_acquire(b->r_rx);
113 struct rtio_sqe *callback_sqe = rtio_sqe_acquire(b->r_rx);
114
115 rtio_sqe_prep_tiny_write(write_len_addr_sqe, iodev, RTIO_PRIO_NORM,
116 &mctp_tx_msg_len_addr, 1, NULL);
117 write_len_addr_sqe->flags |= RTIO_SQE_TRANSACTION;
118
119 rtio_sqe_prep_read(read_len_sqe, iodev, RTIO_PRIO_NORM, &b->rx_buf_len, 1, NULL);
120 read_len_sqe->flags |= RTIO_SQE_CHAINED;
121 read_len_sqe->iodev_flags |= RTIO_IODEV_I2C_RESTART | RTIO_IODEV_I2C_STOP;
122
123 rtio_sqe_prep_callback(callback_sqe, rx_len_completion, b, NULL);
124 callback_sqe->flags |= RTIO_SQE_NO_RESPONSE;
125
126 rtio_submit(b->r_rx, 0);
127 }
128
mctp_tx_requested_isr(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)129 void mctp_tx_requested_isr(const struct device *port, struct gpio_callback *cb,
130 gpio_port_pins_t pins)
131 {
132 struct mctp_i2c_gpio_controller_cb *cb_data =
133 CONTAINER_OF(cb, struct mctp_i2c_gpio_controller_cb, callback);
134 struct mctp_binding_i2c_gpio_controller *b = cb_data->binding;
135
136 LOG_DBG("disable int");
137 gpio_pin_interrupt_configure_dt(&b->endpoint_gpios[cb_data->index], GPIO_INT_DISABLE);
138
139 mpsc_push(&b->rx_q, &cb_data->q);
140
141 /* Atomically start the transfer if nothing is ongoing, if the current tx isn't NULL
142 * a bit is set instead marking the transfer as pending for this matching GPIO and
143 * i2c target
144 */
145 mctp_start_rx(b, false);
146 }
147
mctp_i2c_gpio_controller_tx(struct mctp_binding * binding,struct mctp_pktbuf * pkt)148 int mctp_i2c_gpio_controller_tx(struct mctp_binding *binding, struct mctp_pktbuf *pkt)
149 {
150 int rc = 0;
151
152 /* Which i2c device am I sending this to? */
153 int i;
154 struct mctp_hdr *hdr = mctp_pktbuf_hdr(pkt);
155 struct mctp_binding_i2c_gpio_controller *b =
156 CONTAINER_OF(binding, struct mctp_binding_i2c_gpio_controller, binding);
157 uint8_t pktsize = pkt->end - pkt->start;
158
159 for (i = 0; i < b->num_endpoints; i++) {
160 if (b->endpoint_ids[i] == hdr->dest) {
161 break;
162 }
163 }
164 k_sem_take(b->tx_lock, K_FOREVER);
165
166 const struct rtio_iodev *iodev = b->endpoint_iodevs[i];
167 struct rtio_sqe *write_len_addr_sqe = rtio_sqe_acquire(b->r_tx);
168 struct rtio_sqe *write_len_sqe = rtio_sqe_acquire(b->r_tx);
169 struct rtio_sqe *write_addr_sqe = rtio_sqe_acquire(b->r_tx);
170 struct rtio_sqe *write_data_sqe = rtio_sqe_acquire(b->r_tx);
171 uint8_t addr;
172
173 addr = MCTP_I2C_GPIO_RX_MSG_LEN_ADDR;
174 rtio_sqe_prep_tiny_write(write_len_addr_sqe, iodev, RTIO_PRIO_NORM,
175 &addr, 1, NULL);
176 write_len_addr_sqe->flags |= RTIO_SQE_TRANSACTION;
177 rtio_sqe_prep_tiny_write(write_len_sqe, iodev, RTIO_PRIO_NORM,
178 (uint8_t *)&pktsize, 1, NULL);
179 write_len_sqe->flags |= RTIO_SQE_TRANSACTION;
180 addr = MCTP_I2C_GPIO_RX_MSG_ADDR;
181 rtio_sqe_prep_tiny_write(write_addr_sqe, iodev, RTIO_PRIO_NORM,
182 &addr, 1, NULL);
183 write_addr_sqe->flags |= RTIO_SQE_TRANSACTION;
184 write_addr_sqe->iodev_flags |= RTIO_IODEV_I2C_RESTART;
185 rtio_sqe_prep_write(write_data_sqe, iodev, RTIO_PRIO_NORM,
186 &pkt->data[pkt->start], pktsize, NULL);
187 write_data_sqe->iodev_flags |= RTIO_IODEV_I2C_STOP;
188
189 rtio_submit(b->r_tx, 4);
190
191 struct rtio_cqe *cqe;
192
193 while ((cqe = rtio_cqe_consume(b->r_tx))) {
194 if (cqe->result != 0 && rc == 0) {
195 rc = cqe->result;
196 }
197 rtio_cqe_release(b->r_tx, cqe);
198 }
199
200 if (rc != 0) {
201 LOG_WRN("failed sending mctp message %p", (void *)pkt);
202 }
203
204 k_sem_give(b->tx_lock);
205
206 /* We must *always* return 0 despite errors, otherwise libmctp does not free the packet! */
207 return 0;
208 }
209
mctp_i2c_gpio_controller_start(struct mctp_binding * binding)210 int mctp_i2c_gpio_controller_start(struct mctp_binding *binding)
211 {
212 struct mctp_binding_i2c_gpio_controller *b =
213 CONTAINER_OF(binding, struct mctp_binding_i2c_gpio_controller, binding);
214
215 i2c_recover_bus(b->i2c);
216
217 mpsc_init(&b->rx_q);
218
219 for (int i = 0; i < b->num_endpoints; i++) {
220 gpio_init_callback(&b->endpoint_gpio_cbs[i].callback, &mctp_tx_requested_isr,
221 BIT(b->endpoint_gpios[i].pin));
222 b->endpoint_gpio_cbs[i].binding = b;
223 b->endpoint_gpio_cbs[i].index = i;
224 gpio_add_callback_dt(&b->endpoint_gpios[i], &b->endpoint_gpio_cbs[i].callback);
225 gpio_pin_configure_dt(&b->endpoint_gpios[i], GPIO_INPUT);
226 }
227
228 mctp_binding_set_tx_enabled(binding, true);
229
230 for (int i = 0; i < b->num_endpoints; i++) {
231 gpio_pin_interrupt_configure_dt(&b->endpoint_gpios[i], GPIO_INT_LEVEL_HIGH);
232 }
233
234 LOG_DBG("started");
235
236 return 0;
237 }
238