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