1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * CZ.NIC's Turris Omnia MCU driver 4 * 5 * 2024 by Marek Behún <kabel@kernel.org> 6 */ 7 8 #include <linux/array_size.h> 9 #include <linux/bits.h> 10 #include <linux/device.h> 11 #include <linux/errno.h> 12 #include <linux/hex.h> 13 #include <linux/i2c.h> 14 #include <linux/module.h> 15 #include <linux/string.h> 16 #include <linux/sysfs.h> 17 #include <linux/types.h> 18 19 #include <linux/turris-omnia-mcu-interface.h> 20 #include "turris-omnia-mcu.h" 21 22 #define OMNIA_FW_VERSION_LEN 20 23 #define OMNIA_FW_VERSION_HEX_LEN (2 * OMNIA_FW_VERSION_LEN + 1) 24 #define OMNIA_BOARD_INFO_LEN 16 25 26 int omnia_cmd_write_read(const struct i2c_client *client, 27 void *cmd, unsigned int cmd_len, 28 void *reply, unsigned int reply_len) 29 { 30 struct i2c_msg msgs[2]; 31 int ret, num; 32 33 msgs[0].addr = client->addr; 34 msgs[0].flags = 0; 35 msgs[0].len = cmd_len; 36 msgs[0].buf = cmd; 37 num = 1; 38 39 if (reply_len) { 40 msgs[1].addr = client->addr; 41 msgs[1].flags = I2C_M_RD; 42 msgs[1].len = reply_len; 43 msgs[1].buf = reply; 44 num++; 45 } 46 47 ret = i2c_transfer(client->adapter, msgs, num); 48 if (ret < 0) 49 return ret; 50 if (ret != num) 51 return -EIO; 52 53 return 0; 54 } 55 56 static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader, 57 char version[static OMNIA_FW_VERSION_HEX_LEN]) 58 { 59 u8 reply[OMNIA_FW_VERSION_LEN]; 60 char *p; 61 int err; 62 63 err = omnia_cmd_read(mcu->client, 64 bootloader ? OMNIA_CMD_GET_FW_VERSION_BOOT 65 : OMNIA_CMD_GET_FW_VERSION_APP, 66 reply, sizeof(reply)); 67 if (err) 68 return err; 69 70 p = bin2hex(version, reply, OMNIA_FW_VERSION_LEN); 71 *p = '\0'; 72 73 return 0; 74 } 75 76 static ssize_t fw_version_hash_show(struct device *dev, char *buf, 77 bool bootloader) 78 { 79 struct omnia_mcu *mcu = dev_get_drvdata(dev); 80 char version[OMNIA_FW_VERSION_HEX_LEN]; 81 int err; 82 83 err = omnia_get_version_hash(mcu, bootloader, version); 84 if (err) 85 return err; 86 87 return sysfs_emit(buf, "%s\n", version); 88 } 89 90 static ssize_t fw_version_hash_application_show(struct device *dev, 91 struct device_attribute *a, 92 char *buf) 93 { 94 return fw_version_hash_show(dev, buf, false); 95 } 96 static DEVICE_ATTR_RO(fw_version_hash_application); 97 98 static ssize_t fw_version_hash_bootloader_show(struct device *dev, 99 struct device_attribute *a, 100 char *buf) 101 { 102 return fw_version_hash_show(dev, buf, true); 103 } 104 static DEVICE_ATTR_RO(fw_version_hash_bootloader); 105 106 static ssize_t fw_features_show(struct device *dev, struct device_attribute *a, 107 char *buf) 108 { 109 struct omnia_mcu *mcu = dev_get_drvdata(dev); 110 111 return sysfs_emit(buf, "0x%x\n", mcu->features); 112 } 113 static DEVICE_ATTR_RO(fw_features); 114 115 static ssize_t mcu_type_show(struct device *dev, struct device_attribute *a, 116 char *buf) 117 { 118 struct omnia_mcu *mcu = dev_get_drvdata(dev); 119 120 return sysfs_emit(buf, "%s\n", mcu->type); 121 } 122 static DEVICE_ATTR_RO(mcu_type); 123 124 static ssize_t reset_selector_show(struct device *dev, 125 struct device_attribute *a, char *buf) 126 { 127 u8 reply; 128 int err; 129 130 err = omnia_cmd_read_u8(to_i2c_client(dev), OMNIA_CMD_GET_RESET, 131 &reply); 132 if (err) 133 return err; 134 135 return sysfs_emit(buf, "%d\n", reply); 136 } 137 static DEVICE_ATTR_RO(reset_selector); 138 139 static ssize_t serial_number_show(struct device *dev, 140 struct device_attribute *a, char *buf) 141 { 142 struct omnia_mcu *mcu = dev_get_drvdata(dev); 143 144 return sysfs_emit(buf, "%016llX\n", mcu->board_serial_number); 145 } 146 static DEVICE_ATTR_RO(serial_number); 147 148 static ssize_t first_mac_address_show(struct device *dev, 149 struct device_attribute *a, char *buf) 150 { 151 struct omnia_mcu *mcu = dev_get_drvdata(dev); 152 153 return sysfs_emit(buf, "%pM\n", mcu->board_first_mac); 154 } 155 static DEVICE_ATTR_RO(first_mac_address); 156 157 static ssize_t board_revision_show(struct device *dev, 158 struct device_attribute *a, char *buf) 159 { 160 struct omnia_mcu *mcu = dev_get_drvdata(dev); 161 162 return sysfs_emit(buf, "%u\n", mcu->board_revision); 163 } 164 static DEVICE_ATTR_RO(board_revision); 165 166 static struct attribute *omnia_mcu_base_attrs[] = { 167 &dev_attr_fw_version_hash_application.attr, 168 &dev_attr_fw_version_hash_bootloader.attr, 169 &dev_attr_fw_features.attr, 170 &dev_attr_mcu_type.attr, 171 &dev_attr_reset_selector.attr, 172 &dev_attr_serial_number.attr, 173 &dev_attr_first_mac_address.attr, 174 &dev_attr_board_revision.attr, 175 NULL 176 }; 177 178 static umode_t omnia_mcu_base_attrs_visible(struct kobject *kobj, 179 struct attribute *a, int n) 180 { 181 struct device *dev = kobj_to_dev(kobj); 182 struct omnia_mcu *mcu = dev_get_drvdata(dev); 183 184 if ((a == &dev_attr_serial_number.attr || 185 a == &dev_attr_first_mac_address.attr || 186 a == &dev_attr_board_revision.attr) && 187 !(mcu->features & OMNIA_FEAT_BOARD_INFO)) 188 return 0; 189 190 return a->mode; 191 } 192 193 static const struct attribute_group omnia_mcu_base_group = { 194 .attrs = omnia_mcu_base_attrs, 195 .is_visible = omnia_mcu_base_attrs_visible, 196 }; 197 198 static const struct attribute_group *omnia_mcu_groups[] = { 199 &omnia_mcu_base_group, 200 #ifdef CONFIG_TURRIS_OMNIA_MCU_GPIO 201 &omnia_mcu_gpio_group, 202 #endif 203 #ifdef CONFIG_TURRIS_OMNIA_MCU_SYSOFF_WAKEUP 204 &omnia_mcu_poweroff_group, 205 #endif 206 NULL 207 }; 208 209 static void omnia_mcu_print_version_hash(struct omnia_mcu *mcu, bool bootloader) 210 { 211 const char *type = bootloader ? "bootloader" : "application"; 212 struct device *dev = &mcu->client->dev; 213 char version[OMNIA_FW_VERSION_HEX_LEN]; 214 int err; 215 216 err = omnia_get_version_hash(mcu, bootloader, version); 217 if (err) { 218 dev_err(dev, "Cannot read MCU %s firmware version: %d\n", 219 type, err); 220 return; 221 } 222 223 dev_info(dev, "MCU %s firmware version hash: %s\n", type, version); 224 } 225 226 static const char *omnia_status_to_mcu_type(u16 status) 227 { 228 switch (status & OMNIA_STS_MCU_TYPE_MASK) { 229 case OMNIA_STS_MCU_TYPE_STM32: 230 return "STM32"; 231 case OMNIA_STS_MCU_TYPE_GD32: 232 return "GD32"; 233 case OMNIA_STS_MCU_TYPE_MKL: 234 return "MKL"; 235 default: 236 return "unknown"; 237 } 238 } 239 240 static void omnia_info_missing_feature(struct device *dev, const char *feature) 241 { 242 dev_info(dev, 243 "Your board's MCU firmware does not support the %s feature.\n", 244 feature); 245 } 246 247 static int omnia_mcu_read_features(struct omnia_mcu *mcu) 248 { 249 static const struct { 250 u16 mask; 251 const char *name; 252 } features[] = { 253 #define _DEF_FEAT(_n, _m) { OMNIA_FEAT_ ## _n, _m } 254 _DEF_FEAT(EXT_CMDS, "extended control and status"), 255 _DEF_FEAT(WDT_PING, "watchdog pinging"), 256 _DEF_FEAT(LED_STATE_EXT_MASK, "peripheral LED pins reading"), 257 _DEF_FEAT(NEW_INT_API, "new interrupt API"), 258 _DEF_FEAT(POWEROFF_WAKEUP, "poweroff and wakeup"), 259 _DEF_FEAT(TRNG, "true random number generator"), 260 #undef _DEF_FEAT 261 }; 262 struct i2c_client *client = mcu->client; 263 struct device *dev = &client->dev; 264 bool suggest_fw_upgrade = false; 265 u16 status; 266 int err; 267 268 /* status word holds MCU type, which we need below */ 269 err = omnia_cmd_read_u16(client, OMNIA_CMD_GET_STATUS_WORD, &status); 270 if (err) 271 return err; 272 273 /* 274 * Check whether MCU firmware supports the OMNIA_CMD_GET_FEATURES 275 * command. 276 */ 277 if (status & OMNIA_STS_FEATURES_SUPPORTED) { 278 /* try read 32-bit features */ 279 err = omnia_cmd_read_u32(client, OMNIA_CMD_GET_FEATURES, 280 &mcu->features); 281 if (err) { 282 /* try read 16-bit features */ 283 u16 features16; 284 285 err = omnia_cmd_read_u16(client, OMNIA_CMD_GET_FEATURES, 286 &features16); 287 if (err) 288 return err; 289 290 mcu->features = features16; 291 } else { 292 if (mcu->features & OMNIA_FEAT_FROM_BIT_16_INVALID) 293 mcu->features &= GENMASK(15, 0); 294 } 295 } else { 296 dev_info(dev, 297 "Your board's MCU firmware does not support feature reading.\n"); 298 suggest_fw_upgrade = true; 299 } 300 301 mcu->type = omnia_status_to_mcu_type(status); 302 dev_info(dev, "MCU type %s%s\n", mcu->type, 303 (mcu->features & OMNIA_FEAT_PERIPH_MCU) ? 304 ", with peripheral resets wired" : ""); 305 306 omnia_mcu_print_version_hash(mcu, true); 307 308 if (mcu->features & OMNIA_FEAT_BOOTLOADER) 309 dev_warn(dev, 310 "MCU is running bootloader firmware. Was firmware upgrade interrupted?\n"); 311 else 312 omnia_mcu_print_version_hash(mcu, false); 313 314 for (unsigned int i = 0; i < ARRAY_SIZE(features); i++) { 315 if (mcu->features & features[i].mask) 316 continue; 317 318 omnia_info_missing_feature(dev, features[i].name); 319 suggest_fw_upgrade = true; 320 } 321 322 if (suggest_fw_upgrade) 323 dev_info(dev, 324 "Consider upgrading MCU firmware with the omnia-mcutool utility.\n"); 325 326 return 0; 327 } 328 329 static int omnia_mcu_read_board_info(struct omnia_mcu *mcu) 330 { 331 u8 reply[1 + OMNIA_BOARD_INFO_LEN]; 332 int err; 333 334 err = omnia_cmd_read(mcu->client, OMNIA_CMD_BOARD_INFO_GET, reply, 335 sizeof(reply)); 336 if (err) 337 return err; 338 339 if (reply[0] != OMNIA_BOARD_INFO_LEN) 340 return -EIO; 341 342 mcu->board_serial_number = get_unaligned_le64(&reply[1]); 343 344 /* we can't use ether_addr_copy() because reply is not u16-aligned */ 345 memcpy(mcu->board_first_mac, &reply[9], sizeof(mcu->board_first_mac)); 346 347 mcu->board_revision = reply[15]; 348 349 return 0; 350 } 351 352 static int omnia_mcu_probe(struct i2c_client *client) 353 { 354 struct device *dev = &client->dev; 355 struct omnia_mcu *mcu; 356 int err; 357 358 if (!client->irq) 359 return dev_err_probe(dev, -EINVAL, "IRQ resource not found\n"); 360 361 mcu = devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL); 362 if (!mcu) 363 return -ENOMEM; 364 365 mcu->client = client; 366 i2c_set_clientdata(client, mcu); 367 368 err = omnia_mcu_read_features(mcu); 369 if (err) 370 return dev_err_probe(dev, err, 371 "Cannot determine MCU supported features\n"); 372 373 if (mcu->features & OMNIA_FEAT_BOARD_INFO) { 374 err = omnia_mcu_read_board_info(mcu); 375 if (err) 376 return dev_err_probe(dev, err, 377 "Cannot read board info\n"); 378 } 379 380 err = omnia_mcu_register_sys_off_and_wakeup(mcu); 381 if (err) 382 return err; 383 384 err = omnia_mcu_register_watchdog(mcu); 385 if (err) 386 return err; 387 388 err = omnia_mcu_register_gpiochip(mcu); 389 if (err) 390 return err; 391 392 return omnia_mcu_register_trng(mcu); 393 } 394 395 static const struct of_device_id of_omnia_mcu_match[] = { 396 { .compatible = "cznic,turris-omnia-mcu" }, 397 {} 398 }; 399 400 static struct i2c_driver omnia_mcu_driver = { 401 .probe = omnia_mcu_probe, 402 .driver = { 403 .name = "turris-omnia-mcu", 404 .of_match_table = of_omnia_mcu_match, 405 .dev_groups = omnia_mcu_groups, 406 }, 407 }; 408 module_i2c_driver(omnia_mcu_driver); 409 410 MODULE_AUTHOR("Marek Behun <kabel@kernel.org>"); 411 MODULE_DESCRIPTION("CZ.NIC's Turris Omnia MCU"); 412 MODULE_LICENSE("GPL"); 413