xref: /linux/drivers/mfd/qnap-mcu.c (revision e814f3fd16acfb7f9966773953de8f740a1e3202)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Core driver for the microcontroller unit in QNAP NAS devices that is
4  * connected via a dedicated UART port.
5  *
6  * Copyright (C) 2024 Heiko Stuebner <heiko@sntech.de>
7  */
8 
9 #include <linux/cleanup.h>
10 #include <linux/export.h>
11 #include <linux/mfd/core.h>
12 #include <linux/mfd/qnap-mcu.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/reboot.h>
16 #include <linux/serdev.h>
17 #include <linux/slab.h>
18 
19 /* The longest command found so far is 5 bytes long */
20 #define QNAP_MCU_MAX_CMD_SIZE		5
21 #define QNAP_MCU_MAX_DATA_SIZE		36
22 #define QNAP_MCU_CHECKSUM_SIZE		1
23 
24 #define QNAP_MCU_RX_BUFFER_SIZE		\
25 		(QNAP_MCU_MAX_DATA_SIZE + QNAP_MCU_CHECKSUM_SIZE)
26 
27 #define QNAP_MCU_TX_BUFFER_SIZE		\
28 		(QNAP_MCU_MAX_CMD_SIZE + QNAP_MCU_CHECKSUM_SIZE)
29 
30 #define QNAP_MCU_ACK_LEN		2
31 #define QNAP_MCU_VERSION_LEN		4
32 
33 #define QNAP_MCU_TIMEOUT_MS		500
34 
35 /**
36  * struct qnap_mcu_reply - Reply to a command
37  *
38  * @data:	Buffer to store reply payload in
39  * @length:	Expected reply length, including the checksum
40  * @received:	Received number of bytes, so far
41  * @done:	Triggered when the entire reply has been received
42  */
43 struct qnap_mcu_reply {
44 	u8 *data;
45 	size_t length;
46 	size_t received;
47 	struct completion done;
48 };
49 
50 /**
51  * struct qnap_mcu - QNAP NAS embedded controller
52  *
53  * @serdev:	Pointer to underlying serdev
54  * @bus_lock:	Lock to serialize access to the device
55  * @reply:	Reply data structure
56  * @variant:	Device variant specific information
57  * @version:	MCU firmware version
58  */
59 struct qnap_mcu {
60 	struct serdev_device *serdev;
61 	struct mutex bus_lock;
62 	struct qnap_mcu_reply reply;
63 	const struct qnap_mcu_variant *variant;
64 	u8 version[QNAP_MCU_VERSION_LEN];
65 };
66 
67 /*
68  * The QNAP-MCU uses a basic XOR checksum.
69  * It is always the last byte and XORs the whole previous message.
70  */
71 static u8 qnap_mcu_csum(const u8 *buf, size_t size)
72 {
73 	u8 csum = 0;
74 
75 	while (size--)
76 		csum ^= *buf++;
77 
78 	return csum;
79 }
80 
81 static int qnap_mcu_write(struct qnap_mcu *mcu, const u8 *data, u8 data_size)
82 {
83 	unsigned char tx[QNAP_MCU_TX_BUFFER_SIZE];
84 	size_t length = data_size + QNAP_MCU_CHECKSUM_SIZE;
85 
86 	if (length > sizeof(tx)) {
87 		dev_err(&mcu->serdev->dev, "data too big for transmit buffer");
88 		return -EINVAL;
89 	}
90 
91 	memcpy(tx, data, data_size);
92 	tx[data_size] = qnap_mcu_csum(data, data_size);
93 
94 	serdev_device_write_flush(mcu->serdev);
95 
96 	return serdev_device_write(mcu->serdev, tx, length, HZ);
97 }
98 
99 static size_t qnap_mcu_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t size)
100 {
101 	struct device *dev = &serdev->dev;
102 	struct qnap_mcu *mcu = dev_get_drvdata(dev);
103 	struct qnap_mcu_reply *reply = &mcu->reply;
104 	const u8 *src = buf;
105 	const u8 *end = buf + size;
106 
107 	if (!reply->length) {
108 		dev_warn(dev, "Received %zu bytes, we were not waiting for\n", size);
109 		return size;
110 	}
111 
112 	while (src < end) {
113 		reply->data[reply->received] = *src++;
114 		reply->received++;
115 
116 		if (reply->received == reply->length) {
117 			/* We don't expect any characters from the device now */
118 			reply->length = 0;
119 
120 			complete(&reply->done);
121 
122 			/*
123 			 * We report the consumed number of bytes. If there
124 			 * are still bytes remaining (though there shouldn't)
125 			 * the serdev layer will re-execute this handler with
126 			 * the remainder of the Rx bytes.
127 			 */
128 			return src - buf;
129 		}
130 	}
131 
132 	/*
133 	 * The only way to get out of the above loop and end up here
134 	 * is through consuming all of the supplied data, so here we
135 	 * report that we processed it all.
136 	 */
137 	return size;
138 }
139 
140 static const struct serdev_device_ops qnap_mcu_serdev_device_ops = {
141 	.receive_buf  = qnap_mcu_receive_buf,
142 	.write_wakeup = serdev_device_write_wakeup,
143 };
144 
145 int qnap_mcu_exec(struct qnap_mcu *mcu,
146 		  const u8 *cmd_data, size_t cmd_data_size,
147 		  u8 *reply_data, size_t reply_data_size)
148 {
149 	unsigned char rx[QNAP_MCU_RX_BUFFER_SIZE];
150 	size_t length = reply_data_size + QNAP_MCU_CHECKSUM_SIZE;
151 	struct qnap_mcu_reply *reply = &mcu->reply;
152 	int ret = 0;
153 
154 	if (length > sizeof(rx)) {
155 		dev_err(&mcu->serdev->dev, "expected data too big for receive buffer");
156 		return -EINVAL;
157 	}
158 
159 	mutex_lock(&mcu->bus_lock);
160 
161 	reply->data = rx,
162 	reply->length = length,
163 	reply->received = 0,
164 	reinit_completion(&reply->done);
165 
166 	qnap_mcu_write(mcu, cmd_data, cmd_data_size);
167 
168 	serdev_device_wait_until_sent(mcu->serdev, msecs_to_jiffies(QNAP_MCU_TIMEOUT_MS));
169 
170 	if (!wait_for_completion_timeout(&reply->done, msecs_to_jiffies(QNAP_MCU_TIMEOUT_MS))) {
171 		dev_err(&mcu->serdev->dev, "Command timeout\n");
172 		ret = -ETIMEDOUT;
173 	} else {
174 		u8 crc = qnap_mcu_csum(rx, reply_data_size);
175 
176 		if (crc != rx[reply_data_size]) {
177 			dev_err(&mcu->serdev->dev,
178 				"Invalid Checksum received\n");
179 			ret = -EIO;
180 		} else {
181 			memcpy(reply_data, rx, reply_data_size);
182 		}
183 	}
184 
185 	mutex_unlock(&mcu->bus_lock);
186 	return ret;
187 }
188 EXPORT_SYMBOL_GPL(qnap_mcu_exec);
189 
190 int qnap_mcu_exec_with_ack(struct qnap_mcu *mcu,
191 			   const u8 *cmd_data, size_t cmd_data_size)
192 {
193 	u8 ack[QNAP_MCU_ACK_LEN];
194 	int ret;
195 
196 	ret = qnap_mcu_exec(mcu, cmd_data, cmd_data_size, ack, sizeof(ack));
197 	if (ret)
198 		return ret;
199 
200 	/* Should return @0 */
201 	if (ack[0] != '@' || ack[1] != '0') {
202 		dev_err(&mcu->serdev->dev, "Did not receive ack\n");
203 		return -EIO;
204 	}
205 
206 	return 0;
207 }
208 EXPORT_SYMBOL_GPL(qnap_mcu_exec_with_ack);
209 
210 static int qnap_mcu_get_version(struct qnap_mcu *mcu)
211 {
212 	const u8 cmd[] = { '%', 'V' };
213 	u8 rx[14];
214 	int ret;
215 
216 	/* Reply is the 2 command-bytes + 4 bytes describing the version */
217 	ret = qnap_mcu_exec(mcu, cmd, sizeof(cmd), rx, QNAP_MCU_VERSION_LEN + 2);
218 	if (ret)
219 		return ret;
220 
221 	memcpy(mcu->version, &rx[2], QNAP_MCU_VERSION_LEN);
222 
223 	return 0;
224 }
225 
226 /*
227  * The MCU controls power to the peripherals but not the CPU.
228  *
229  * So using the PMIC to power off the system keeps the MCU and hard-drives
230  * running. This also then prevents the system from turning back on until
231  * the MCU is turned off by unplugging the power cable.
232  * Turning off the MCU alone on the other hand turns off the hard drives,
233  * LEDs, etc while the main SoC stays running - including its network ports.
234  */
235 static int qnap_mcu_power_off(struct sys_off_data *data)
236 {
237 	const u8 cmd[] = { '@', 'C', '0' };
238 	struct qnap_mcu *mcu = data->cb_data;
239 	int ret;
240 
241 	ret = qnap_mcu_exec_with_ack(mcu, cmd, sizeof(cmd));
242 	if (ret) {
243 		dev_err(&mcu->serdev->dev, "MCU poweroff failed %d\n", ret);
244 		return NOTIFY_STOP;
245 	}
246 
247 	return NOTIFY_DONE;
248 }
249 
250 static const struct qnap_mcu_variant qnap_ts433_mcu = {
251 	.baud_rate = 115200,
252 	.num_drives = 4,
253 	.fan_pwm_min = 51,  /* Specified in original model.conf */
254 	.fan_pwm_max = 255,
255 	.usb_led = true,
256 };
257 
258 static struct mfd_cell qnap_mcu_cells[] = {
259 	{ .name = "qnap-mcu-input", },
260 	{ .name = "qnap-mcu-leds", },
261 	{ .name = "qnap-mcu-hwmon", }
262 };
263 
264 static int qnap_mcu_probe(struct serdev_device *serdev)
265 {
266 	struct device *dev = &serdev->dev;
267 	struct qnap_mcu *mcu;
268 	int ret;
269 
270 	mcu = devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL);
271 	if (!mcu)
272 		return -ENOMEM;
273 
274 	mcu->serdev = serdev;
275 	dev_set_drvdata(dev, mcu);
276 
277 	mcu->variant = of_device_get_match_data(dev);
278 	if (!mcu->variant)
279 		return -ENODEV;
280 
281 	mutex_init(&mcu->bus_lock);
282 	init_completion(&mcu->reply.done);
283 
284 	serdev_device_set_client_ops(serdev, &qnap_mcu_serdev_device_ops);
285 	ret = devm_serdev_device_open(dev, serdev);
286 	if (ret)
287 		return ret;
288 
289 	serdev_device_set_baudrate(serdev, mcu->variant->baud_rate);
290 	serdev_device_set_flow_control(serdev, false);
291 
292 	ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
293 	if (ret)
294 		return dev_err_probe(dev, ret, "Failed to set parity\n");
295 
296 	ret = qnap_mcu_get_version(mcu);
297 	if (ret)
298 		return ret;
299 
300 	ret = devm_register_sys_off_handler(dev,
301 					    SYS_OFF_MODE_POWER_OFF_PREPARE,
302 					    SYS_OFF_PRIO_DEFAULT,
303 					    &qnap_mcu_power_off, mcu);
304 	if (ret)
305 		return dev_err_probe(dev, ret,
306 				     "Failed to register poweroff handler\n");
307 
308 	for (int i = 0; i < ARRAY_SIZE(qnap_mcu_cells); i++) {
309 		qnap_mcu_cells[i].platform_data = mcu->variant;
310 		qnap_mcu_cells[i].pdata_size = sizeof(*mcu->variant);
311 	}
312 
313 	ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, qnap_mcu_cells,
314 				   ARRAY_SIZE(qnap_mcu_cells), NULL, 0, NULL);
315 	if (ret)
316 		return dev_err_probe(dev, ret, "Failed to add child devices\n");
317 
318 	return 0;
319 }
320 
321 static const struct of_device_id qnap_mcu_dt_ids[] = {
322 	{ .compatible = "qnap,ts433-mcu", .data = &qnap_ts433_mcu },
323 	{ /* sentinel */ }
324 };
325 MODULE_DEVICE_TABLE(of, qnap_mcu_dt_ids);
326 
327 static struct serdev_device_driver qnap_mcu_drv = {
328 	.probe = qnap_mcu_probe,
329 	.driver = {
330 		.name = "qnap-mcu",
331 		.of_match_table = qnap_mcu_dt_ids,
332 	},
333 };
334 module_serdev_device_driver(qnap_mcu_drv);
335 
336 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
337 MODULE_DESCRIPTION("QNAP MCU core driver");
338 MODULE_LICENSE("GPL");
339