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_ERROR_SIZE 2 23 #define QNAP_MCU_CHECKSUM_SIZE 1 24 25 #define QNAP_MCU_RX_BUFFER_SIZE \ 26 (QNAP_MCU_MAX_DATA_SIZE + QNAP_MCU_CHECKSUM_SIZE) 27 28 #define QNAP_MCU_TX_BUFFER_SIZE \ 29 (QNAP_MCU_MAX_CMD_SIZE + QNAP_MCU_CHECKSUM_SIZE) 30 31 #define QNAP_MCU_ACK_LEN 2 32 #define QNAP_MCU_VERSION_LEN 4 33 34 #define QNAP_MCU_TIMEOUT_MS 500 35 36 /** 37 * struct qnap_mcu_reply - Reply to a command 38 * 39 * @data: Buffer to store reply payload in 40 * @length: Expected reply length, including the checksum 41 * @received: Received number of bytes, so far 42 * @done: Triggered when the entire reply has been received 43 */ 44 struct qnap_mcu_reply { 45 u8 *data; 46 size_t length; 47 size_t received; 48 struct completion done; 49 }; 50 51 /** 52 * struct qnap_mcu - QNAP NAS embedded controller 53 * 54 * @serdev: Pointer to underlying serdev 55 * @bus_lock: Lock to serialize access to the device 56 * @reply: Reply data structure 57 * @variant: Device variant specific information 58 * @version: MCU firmware version 59 */ 60 struct qnap_mcu { 61 struct serdev_device *serdev; 62 struct mutex bus_lock; 63 struct qnap_mcu_reply reply; 64 const struct qnap_mcu_variant *variant; 65 u8 version[QNAP_MCU_VERSION_LEN]; 66 }; 67 68 /* 69 * The QNAP-MCU uses a basic XOR checksum. 70 * It is always the last byte and XORs the whole previous message. 71 */ 72 static u8 qnap_mcu_csum(const u8 *buf, size_t size) 73 { 74 u8 csum = 0; 75 76 while (size--) 77 csum ^= *buf++; 78 79 return csum; 80 } 81 82 static bool qnap_mcu_verify_checksum(const u8 *buf, size_t size) 83 { 84 u8 crc = qnap_mcu_csum(buf, size - QNAP_MCU_CHECKSUM_SIZE); 85 86 return crc == buf[size - QNAP_MCU_CHECKSUM_SIZE]; 87 } 88 89 static int qnap_mcu_write(struct qnap_mcu *mcu, const u8 *data, u8 data_size) 90 { 91 unsigned char tx[QNAP_MCU_TX_BUFFER_SIZE]; 92 size_t length = data_size + QNAP_MCU_CHECKSUM_SIZE; 93 94 if (length > sizeof(tx)) { 95 dev_err(&mcu->serdev->dev, "data too big for transmit buffer"); 96 return -EINVAL; 97 } 98 99 memcpy(tx, data, data_size); 100 tx[data_size] = qnap_mcu_csum(data, data_size); 101 102 serdev_device_write_flush(mcu->serdev); 103 104 return serdev_device_write(mcu->serdev, tx, length, HZ); 105 } 106 107 static bool qnap_mcu_is_error_msg(size_t size) 108 { 109 return (size == QNAP_MCU_ERROR_SIZE + QNAP_MCU_CHECKSUM_SIZE); 110 } 111 112 static bool qnap_mcu_reply_is_generic_error(unsigned char *buf, size_t size) 113 { 114 if (!qnap_mcu_is_error_msg(size)) 115 return false; 116 117 if (buf[0] == '@' && buf[1] == '9') 118 return true; 119 120 return false; 121 } 122 123 static bool qnap_mcu_reply_is_checksum_error(unsigned char *buf, size_t size) 124 { 125 if (!qnap_mcu_is_error_msg(size)) 126 return false; 127 128 if (buf[0] == '@' && buf[1] == '8') 129 return true; 130 131 return false; 132 } 133 134 static bool qnap_mcu_reply_is_any_error(struct qnap_mcu *mcu, unsigned char *buf, size_t size) 135 { 136 if (qnap_mcu_reply_is_generic_error(buf, size)) { 137 dev_err(&mcu->serdev->dev, "Controller sent generic error response\n"); 138 return true; 139 } 140 141 if (qnap_mcu_reply_is_checksum_error(buf, size)) { 142 dev_err(&mcu->serdev->dev, "Controller received invalid checksum for the command\n"); 143 return true; 144 } 145 146 return false; 147 } 148 149 static size_t qnap_mcu_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t size) 150 { 151 struct device *dev = &serdev->dev; 152 struct qnap_mcu *mcu = dev_get_drvdata(dev); 153 struct qnap_mcu_reply *reply = &mcu->reply; 154 const u8 *src = buf; 155 const u8 *end = buf + size; 156 157 if (!reply->length) { 158 dev_warn(dev, "Received %zu bytes, we were not waiting for\n", size); 159 return size; 160 } 161 162 while (src < end) { 163 reply->data[reply->received] = *src++; 164 reply->received++; 165 166 if (reply->received == reply->length) { 167 /* We don't expect any characters from the device now */ 168 reply->length = 0; 169 170 complete(&reply->done); 171 172 /* 173 * We report the consumed number of bytes. If there 174 * are still bytes remaining (though there shouldn't) 175 * the serdev layer will re-execute this handler with 176 * the remainder of the Rx bytes. 177 */ 178 return src - buf; 179 } 180 } 181 182 /* 183 * We received everything the uart had to offer for now. 184 * This could mean that either the uart will send more in a 2nd 185 * receive run, or that the MCU cut the reply short because it 186 * sent an error code instead of the expected reply. 187 * 188 * So check if the received data has the correct size for an error 189 * reply and if it matches, is an actual error code. 190 */ 191 if (qnap_mcu_is_error_msg(reply->received) && 192 qnap_mcu_verify_checksum(reply->data, reply->received) && 193 qnap_mcu_reply_is_any_error(mcu, reply->data, reply->received)) { 194 /* The reply was an error code, we're done */ 195 reply->length = 0; 196 197 complete(&reply->done); 198 } 199 200 /* 201 * The only way to get out of the above loop and end up here 202 * is through consuming all of the supplied data, so here we 203 * report that we processed it all. 204 */ 205 return size; 206 } 207 208 static const struct serdev_device_ops qnap_mcu_serdev_device_ops = { 209 .receive_buf = qnap_mcu_receive_buf, 210 .write_wakeup = serdev_device_write_wakeup, 211 }; 212 213 int qnap_mcu_exec(struct qnap_mcu *mcu, 214 const u8 *cmd_data, size_t cmd_data_size, 215 u8 *reply_data, size_t reply_data_size) 216 { 217 unsigned char rx[QNAP_MCU_RX_BUFFER_SIZE]; 218 size_t length = reply_data_size + QNAP_MCU_CHECKSUM_SIZE; 219 struct qnap_mcu_reply *reply = &mcu->reply; 220 int ret = 0; 221 222 if (length > sizeof(rx)) { 223 dev_err(&mcu->serdev->dev, "expected data too big for receive buffer"); 224 return -EINVAL; 225 } 226 227 guard(mutex)(&mcu->bus_lock); 228 229 reply->data = rx; 230 reply->length = length; 231 reply->received = 0; 232 reinit_completion(&reply->done); 233 234 ret = qnap_mcu_write(mcu, cmd_data, cmd_data_size); 235 if (ret < 0) 236 return ret; 237 238 serdev_device_wait_until_sent(mcu->serdev, msecs_to_jiffies(QNAP_MCU_TIMEOUT_MS)); 239 240 if (!wait_for_completion_timeout(&reply->done, msecs_to_jiffies(QNAP_MCU_TIMEOUT_MS))) { 241 dev_err(&mcu->serdev->dev, "Command timeout\n"); 242 return -ETIMEDOUT; 243 } 244 245 if (!qnap_mcu_verify_checksum(rx, reply->received)) { 246 dev_err(&mcu->serdev->dev, "Invalid Checksum received from controller\n"); 247 return -EPROTO; 248 } 249 250 if (qnap_mcu_reply_is_any_error(mcu, rx, reply->received)) 251 return -EPROTO; 252 253 memcpy(reply_data, rx, reply_data_size); 254 255 return 0; 256 } 257 EXPORT_SYMBOL_GPL(qnap_mcu_exec); 258 259 int qnap_mcu_exec_with_ack(struct qnap_mcu *mcu, 260 const u8 *cmd_data, size_t cmd_data_size) 261 { 262 u8 ack[QNAP_MCU_ACK_LEN]; 263 int ret; 264 265 ret = qnap_mcu_exec(mcu, cmd_data, cmd_data_size, ack, sizeof(ack)); 266 if (ret) 267 return ret; 268 269 /* Should return @0 */ 270 if (ack[0] != '@' || ack[1] != '0') { 271 dev_err(&mcu->serdev->dev, "Did not receive ack\n"); 272 return -EIO; 273 } 274 275 return 0; 276 } 277 EXPORT_SYMBOL_GPL(qnap_mcu_exec_with_ack); 278 279 static int qnap_mcu_get_version(struct qnap_mcu *mcu) 280 { 281 const u8 cmd[] = { '%', 'V' }; 282 u8 rx[14]; 283 int ret; 284 285 /* Reply is the 2 command-bytes + 4 bytes describing the version */ 286 ret = qnap_mcu_exec(mcu, cmd, sizeof(cmd), rx, QNAP_MCU_VERSION_LEN + 2); 287 if (ret) 288 return ret; 289 290 memcpy(mcu->version, &rx[2], QNAP_MCU_VERSION_LEN); 291 292 return 0; 293 } 294 295 /* 296 * The MCU controls power to the peripherals but not the CPU. 297 * 298 * So using the PMIC to power off the system keeps the MCU and hard-drives 299 * running. This also then prevents the system from turning back on until 300 * the MCU is turned off by unplugging the power cable. 301 * Turning off the MCU alone on the other hand turns off the hard drives, 302 * LEDs, etc while the main SoC stays running - including its network ports. 303 */ 304 static int qnap_mcu_power_off(struct sys_off_data *data) 305 { 306 const u8 cmd[] = { '@', 'C', '0' }; 307 struct qnap_mcu *mcu = data->cb_data; 308 int ret; 309 310 ret = qnap_mcu_exec_with_ack(mcu, cmd, sizeof(cmd)); 311 if (ret) { 312 dev_err(&mcu->serdev->dev, "MCU poweroff failed %d\n", ret); 313 return NOTIFY_STOP; 314 } 315 316 return NOTIFY_DONE; 317 } 318 319 static const struct qnap_mcu_variant qnap_ts133_mcu = { 320 .baud_rate = 115200, 321 .num_drives = 1, 322 .fan_pwm_min = 51, /* Specified in original model.conf */ 323 .fan_pwm_max = 255, 324 .usb_led = false, 325 }; 326 327 static const struct qnap_mcu_variant qnap_ts233_mcu = { 328 .baud_rate = 115200, 329 .num_drives = 2, 330 .fan_pwm_min = 51, /* Specified in original model.conf */ 331 .fan_pwm_max = 255, 332 .usb_led = true, 333 }; 334 335 static const struct qnap_mcu_variant qnap_ts433_mcu = { 336 .baud_rate = 115200, 337 .num_drives = 4, 338 .fan_pwm_min = 51, /* Specified in original model.conf */ 339 .fan_pwm_max = 255, 340 .usb_led = true, 341 }; 342 343 static struct mfd_cell qnap_mcu_cells[] = { 344 { .name = "qnap-mcu-eeprom", }, 345 { .name = "qnap-mcu-input", }, 346 { .name = "qnap-mcu-leds", }, 347 { .name = "qnap-mcu-hwmon", } 348 }; 349 350 static int qnap_mcu_probe(struct serdev_device *serdev) 351 { 352 struct device *dev = &serdev->dev; 353 struct qnap_mcu *mcu; 354 int ret; 355 356 mcu = devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL); 357 if (!mcu) 358 return -ENOMEM; 359 360 mcu->serdev = serdev; 361 dev_set_drvdata(dev, mcu); 362 363 mcu->variant = of_device_get_match_data(dev); 364 if (!mcu->variant) 365 return -ENODEV; 366 367 mutex_init(&mcu->bus_lock); 368 init_completion(&mcu->reply.done); 369 370 serdev_device_set_client_ops(serdev, &qnap_mcu_serdev_device_ops); 371 ret = devm_serdev_device_open(dev, serdev); 372 if (ret) 373 return ret; 374 375 serdev_device_set_baudrate(serdev, mcu->variant->baud_rate); 376 serdev_device_set_flow_control(serdev, false); 377 378 ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); 379 if (ret) 380 return dev_err_probe(dev, ret, "Failed to set parity\n"); 381 382 ret = qnap_mcu_get_version(mcu); 383 if (ret) 384 return ret; 385 386 ret = devm_register_sys_off_handler(dev, 387 SYS_OFF_MODE_POWER_OFF_PREPARE, 388 SYS_OFF_PRIO_DEFAULT, 389 &qnap_mcu_power_off, mcu); 390 if (ret) 391 return dev_err_probe(dev, ret, 392 "Failed to register poweroff handler\n"); 393 394 for (int i = 0; i < ARRAY_SIZE(qnap_mcu_cells); i++) { 395 qnap_mcu_cells[i].platform_data = mcu->variant; 396 qnap_mcu_cells[i].pdata_size = sizeof(*mcu->variant); 397 } 398 399 ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, qnap_mcu_cells, 400 ARRAY_SIZE(qnap_mcu_cells), NULL, 0, NULL); 401 if (ret) 402 return dev_err_probe(dev, ret, "Failed to add child devices\n"); 403 404 return 0; 405 } 406 407 static const struct of_device_id qnap_mcu_dt_ids[] = { 408 { .compatible = "qnap,ts133-mcu", .data = &qnap_ts133_mcu }, 409 { .compatible = "qnap,ts233-mcu", .data = &qnap_ts233_mcu }, 410 { .compatible = "qnap,ts433-mcu", .data = &qnap_ts433_mcu }, 411 { /* sentinel */ } 412 }; 413 MODULE_DEVICE_TABLE(of, qnap_mcu_dt_ids); 414 415 static struct serdev_device_driver qnap_mcu_drv = { 416 .probe = qnap_mcu_probe, 417 .driver = { 418 .name = "qnap-mcu", 419 .of_match_table = qnap_mcu_dt_ids, 420 }, 421 }; 422 module_serdev_device_driver(qnap_mcu_drv); 423 424 MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 425 MODULE_DESCRIPTION("QNAP MCU core driver"); 426 MODULE_LICENSE("GPL"); 427