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