1 /*
2  * Copyright (c) 2025 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  */
7 
8 #include "zephyr/pmci/mctp/mctp_i2c_gpio_common.h"
9 #include <zephyr/sys/__assert.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/drivers/uart.h>
12 #include <zephyr/pmci/mctp/mctp_i2c_gpio_target.h>
13 #include <crc-16-ccitt.h>
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(mctp_i2c_gpio_target, CONFIG_MCTP_LOG_LEVEL);
17 
mctp_i2c_gpio_target_write_requested(struct i2c_target_config * config)18 int mctp_i2c_gpio_target_write_requested(struct i2c_target_config *config)
19 {
20 
21 	struct mctp_binding_i2c_gpio_target *b =
22 		CONTAINER_OF(config, struct mctp_binding_i2c_gpio_target, i2c_target_cfg);
23 
24 	if (b->rxtx || b->reg_addr == MCTP_I2C_GPIO_INVALID_ADDR) {
25 		/* Reset our state */
26 		b->reg_addr = MCTP_I2C_GPIO_INVALID_ADDR;
27 		b->rxtx = false;
28 		b->rx_idx = 0;
29 	}
30 
31 	return 0;
32 }
33 
mctp_i2c_gpio_target_write_received(struct i2c_target_config * config,uint8_t val)34 int mctp_i2c_gpio_target_write_received(struct i2c_target_config *config, uint8_t val)
35 {
36 	struct mctp_binding_i2c_gpio_target *b =
37 		CONTAINER_OF(config, struct mctp_binding_i2c_gpio_target, i2c_target_cfg);
38 	int ret = 0;
39 
40 	switch (b->reg_addr) {
41 	case MCTP_I2C_GPIO_INVALID_ADDR:
42 		b->rxtx = false;
43 		b->reg_addr = val;
44 		break;
45 	case MCTP_I2C_GPIO_RX_MSG_LEN_ADDR:
46 		b->rxtx = true;
47 		b->rx_pkt = mctp_pktbuf_alloc(&b->binding, (size_t)val);
48 		break;
49 	case MCTP_I2C_GPIO_RX_MSG_ADDR:
50 		b->rxtx = true;
51 		b->rx_pkt->data[b->rx_idx] = val;
52 		b->rx_idx += 1;
53 
54 		/* buffer full */
55 		if (b->rx_idx >= b->rx_pkt->size) {
56 			ret = -ENOMEM;
57 		}
58 		break;
59 	default:
60 		LOG_ERR("Write when reg_addr is %d", b->reg_addr);
61 		ret = -EIO;
62 		break;
63 	}
64 
65 	return ret;
66 }
67 
mctp_i2c_gpio_target_read_requested(struct i2c_target_config * config,uint8_t * val)68 int mctp_i2c_gpio_target_read_requested(struct i2c_target_config *config, uint8_t *val)
69 {
70 	struct mctp_binding_i2c_gpio_target *b =
71 		CONTAINER_OF(config, struct mctp_binding_i2c_gpio_target, i2c_target_cfg);
72 	uint8_t pkt_len;
73 	int ret = 0;
74 
75 	switch (b->reg_addr) {
76 	case MCTP_I2C_GPIO_TX_MSG_LEN_ADDR:
77 		b->rxtx = true;
78 		if (b->tx_pkt == NULL) {
79 			LOG_WRN("empty packet?");
80 			pkt_len = 0;
81 		} else {
82 			pkt_len = (uint8_t)(b->tx_pkt->end - b->tx_pkt->start);
83 		}
84 		*val = pkt_len;
85 		break;
86 	case MCTP_I2C_GPIO_TX_MSG_ADDR:
87 		b->rxtx = true;
88 		*val = b->tx_pkt->data[b->tx_pkt->start];
89 		b->tx_idx = b->tx_pkt->start;
90 		break;
91 	default:
92 		LOG_WRN("invalid rre reg %d", b->reg_addr);
93 		ret = -EINVAL;
94 	}
95 
96 	return ret;
97 }
98 
mctp_i2c_gpio_target_read_processed(struct i2c_target_config * config,uint8_t * val)99 int mctp_i2c_gpio_target_read_processed(struct i2c_target_config *config, uint8_t *val)
100 {
101 	struct mctp_binding_i2c_gpio_target *b =
102 		CONTAINER_OF(config, struct mctp_binding_i2c_gpio_target, i2c_target_cfg);
103 
104 	b->tx_idx += 1;
105 
106 	if (b->reg_addr != MCTP_I2C_GPIO_TX_MSG_ADDR) {
107 		goto out;
108 	}
109 
110 	if (b->tx_idx > b->tx_pkt->end) {
111 		LOG_WRN("rrp past end reg %d", b->reg_addr);
112 		return -EIO;
113 	}
114 
115 	*val = b->tx_pkt->data[b->tx_idx];
116 
117 out:
118 	return 0;
119 }
120 
mctp_i2c_gpio_target_stop(struct i2c_target_config * config)121 int mctp_i2c_gpio_target_stop(struct i2c_target_config *config)
122 {
123 	struct mctp_binding_i2c_gpio_target *b =
124 		CONTAINER_OF(config, struct mctp_binding_i2c_gpio_target, i2c_target_cfg);
125 	uint8_t pkt_len;
126 
127 	if (b->rxtx) {
128 		switch (b->reg_addr) {
129 		case MCTP_I2C_GPIO_TX_MSG_ADDR:
130 			pkt_len = (b->tx_pkt->end - b->tx_pkt->start);
131 			if (b->tx_idx < pkt_len - 1) {
132 				LOG_WRN("Only %d of %d bytes of the transmit packet were read",
133 					b->tx_idx, pkt_len);
134 			}
135 			b->tx_pkt = NULL;
136 			k_sem_give(b->tx_complete);
137 			break;
138 
139 		case MCTP_I2C_GPIO_RX_MSG_ADDR:
140 			LOG_DBG("stop rx msg, give pkt");
141 			/* Give message to mctp to process */
142 			mctp_bus_rx(&b->binding, b->rx_pkt);
143 			b->rx_pkt = NULL;
144 			break;
145 		case MCTP_I2C_GPIO_RX_MSG_LEN_ADDR:
146 		case MCTP_I2C_GPIO_TX_MSG_LEN_ADDR:
147 			break;
148 		default:
149 			LOG_WRN("unexpected stop for reg %d", b->reg_addr);
150 			break;
151 		}
152 	}
153 
154 	return 0;
155 }
156 
157 const struct i2c_target_callbacks mctp_i2c_gpio_target_callbacks = {
158 	.write_requested = mctp_i2c_gpio_target_write_requested,
159 	.read_requested = mctp_i2c_gpio_target_read_requested,
160 	.write_received = mctp_i2c_gpio_target_write_received,
161 	.read_processed = mctp_i2c_gpio_target_read_processed,
162 	.stop = mctp_i2c_gpio_target_stop,
163 };
164 
165 /*
166  * libmctp wants us to return once the packet is sent not before
167  * so the entire process of flagging the tx with gpio, waiting on the read,
168  * needs to complete before we can move on.
169  *
170  * this is called for each packet in the packet queue libmctp provides
171  */
mctp_i2c_gpio_target_tx(struct mctp_binding * binding,struct mctp_pktbuf * pkt)172 int mctp_i2c_gpio_target_tx(struct mctp_binding *binding, struct mctp_pktbuf *pkt)
173 {
174 	struct mctp_binding_i2c_gpio_target *b =
175 		CONTAINER_OF(binding, struct mctp_binding_i2c_gpio_target, binding);
176 	int rc;
177 
178 	k_sem_take(b->tx_lock, K_FOREVER);
179 
180 	b->tx_pkt = pkt;
181 
182 	rc = gpio_pin_set_dt(&b->endpoint_gpio, 1);
183 	if (rc != 0) {
184 		LOG_ERR("failed to set gpio pin");
185 		b->tx_pkt = NULL;
186 		goto out;
187 	}
188 
189 	k_sem_take(b->tx_complete, K_FOREVER);
190 
191 	rc = gpio_pin_set_dt(&b->endpoint_gpio, 0);
192 	if (rc != 0) {
193 		LOG_ERR("failed to clear gpio pin");
194 	}
195 
196 out:
197 	k_sem_give(b->tx_lock);
198 	return rc;
199 }
200 
mctp_i2c_gpio_target_start(struct mctp_binding * binding)201 int mctp_i2c_gpio_target_start(struct mctp_binding *binding)
202 {
203 	struct mctp_binding_i2c_gpio_target *b =
204 		CONTAINER_OF(binding, struct mctp_binding_i2c_gpio_target, binding);
205 	int rc;
206 
207 	/* Register i2c target */
208 	rc = i2c_target_register(b->i2c, &b->i2c_target_cfg);
209 	if (rc != 0) {
210 		LOG_ERR("failed to register i2c target");
211 		goto out;
212 	}
213 
214 	/* Configure pin to use as data ready signaling */
215 	rc = gpio_pin_configure_dt(&b->endpoint_gpio, GPIO_OUTPUT_INACTIVE);
216 	if (rc != 0) {
217 		LOG_ERR("failed to configure gpio");
218 		goto out;
219 	}
220 
221 	mctp_binding_set_tx_enabled(binding, true);
222 
223 out:
224 	return 0;
225 }
226