Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform: cznic: Add preliminary support for Turris Omnia MCU

Add the basic skeleton for a new platform driver for the microcontroller
found on the Turris Omnia board.

Signed-off-by: Marek Behún <kabel@kernel.org>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Link: https://lore.kernel.org/r/20240701113010.16447-3-kabel@kernel.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

authored by

Marek Behún and committed by
Arnd Bergmann
992f1a3d f5e6f47f

+833
+81
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
··· 1 + What: /sys/bus/i2c/devices/<mcu_device>/board_revision 2 + Date: September 2024 3 + KernelVersion: 6.11 4 + Contact: Marek Behún <kabel@kernel.org> 5 + Description: (RO) Contains board revision number. 6 + 7 + Only available if board information is burned in the MCU (older 8 + revisions have board information burned in the ATSHA204-A chip). 9 + 10 + Format: %u. 11 + 12 + What: /sys/bus/i2c/devices/<mcu_device>/first_mac_address 13 + Date: September 2024 14 + KernelVersion: 6.11 15 + Contact: Marek Behún <kabel@kernel.org> 16 + Description: (RO) Contains device first MAC address. Each Turris Omnia is 17 + allocated 3 MAC addresses. The two additional addresses are 18 + computed from the first one by incrementing it. 19 + 20 + Only available if board information is burned in the MCU (older 21 + revisions have board information burned in the ATSHA204-A chip). 22 + 23 + Format: %pM. 24 + 25 + What: /sys/bus/i2c/devices/<mcu_device>/fw_features 26 + Date: September 2024 27 + KernelVersion: 6.11 28 + Contact: Marek Behún <kabel@kernel.org> 29 + Description: (RO) Newer versions of the microcontroller firmware report the 30 + features they support. These can be read from this file. If the 31 + MCU firmware is too old, this file reads 0x0. 32 + 33 + Format: 0x%x. 34 + 35 + What: /sys/bus/i2c/devices/<mcu_device>/fw_version_hash_application 36 + Date: September 2024 37 + KernelVersion: 6.11 38 + Contact: Marek Behún <kabel@kernel.org> 39 + Description: (RO) Contains the version hash (commit hash) of the application 40 + part of the microcontroller firmware. 41 + 42 + Format: %s. 43 + 44 + What: /sys/bus/i2c/devices/<mcu_device>/fw_version_hash_bootloader 45 + Date: September 2024 46 + KernelVersion: 6.11 47 + Contact: Marek Behún <kabel@kernel.org> 48 + Description: (RO) Contains the version hash (commit hash) of the bootloader 49 + part of the microcontroller firmware. 50 + 51 + Format: %s. 52 + 53 + What: /sys/bus/i2c/devices/<mcu_device>/mcu_type 54 + Date: September 2024 55 + KernelVersion: 6.11 56 + Contact: Marek Behún <kabel@kernel.org> 57 + Description: (RO) Contains the microcontroller type (STM32, GD32, MKL). 58 + 59 + Format: %s. 60 + 61 + What: /sys/bus/i2c/devices/<mcu_device>/reset_selector 62 + Date: September 2024 63 + KernelVersion: 6.11 64 + Contact: Marek Behún <kabel@kernel.org> 65 + Description: (RO) Contains the selected factory reset level, determined by 66 + how long the rear reset button was held by the user during board 67 + reset. 68 + 69 + Format: %i. 70 + 71 + What: /sys/bus/i2c/devices/<mcu_device>/serial_number 72 + Date: September 2024 73 + KernelVersion: 6.11 74 + Contact: Marek Behún <kabel@kernel.org> 75 + Description: (RO) Contains the 64-bit board serial number in hexadecimal 76 + format. 77 + 78 + Only available if board information is burned in the MCU (older 79 + revisions have board information burned in the ATSHA204-A chip). 80 + 81 + Format: %016X.
+3
MAINTAINERS
··· 2206 2206 S: Maintained 2207 2207 W: https://www.turris.cz/ 2208 2208 F: Documentation/ABI/testing/debugfs-moxtet 2209 + F: Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu 2209 2210 F: Documentation/ABI/testing/sysfs-bus-moxtet-devices 2210 2211 F: Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm 2211 2212 F: Documentation/devicetree/bindings/bus/moxtet.txt ··· 2220 2219 F: drivers/gpio/gpio-moxtet.c 2221 2220 F: drivers/leds/leds-turris-omnia.c 2222 2221 F: drivers/mailbox/armada-37xx-rwtm-mailbox.c 2222 + F: drivers/platform/cznic/ 2223 2223 F: drivers/watchdog/armada_37xx_wdt.c 2224 2224 F: include/dt-bindings/bus/moxtet.h 2225 2225 F: include/linux/armada-37xx-rwtm-mailbox.h 2226 2226 F: include/linux/moxtet.h 2227 + F: include/linux/turris-omnia-mcu-interface.h 2227 2228 2228 2229 ARM/FARADAY FA526 PORT 2229 2230 M: Hans Ulli Kroll <ulli.kroll@googlemail.com>
+2
drivers/platform/Kconfig
··· 7 7 8 8 source "drivers/platform/chrome/Kconfig" 9 9 10 + source "drivers/platform/cznic/Kconfig" 11 + 10 12 source "drivers/platform/mellanox/Kconfig" 11 13 12 14 source "drivers/platform/olpc/Kconfig"
+1
drivers/platform/Makefile
··· 10 10 obj-$(CONFIG_OLPC_EC) += olpc/ 11 11 obj-$(CONFIG_GOLDFISH) += goldfish/ 12 12 obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ 13 + obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/ 13 14 obj-$(CONFIG_SURFACE_PLATFORMS) += surface/ 14 15 obj-$(CONFIG_ARM64) += arm64/
+25
drivers/platform/cznic/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # 3 + # For a description of the syntax of this configuration file, 4 + # see Documentation/kbuild/kconfig-language.rst. 5 + # 6 + 7 + menuconfig CZNIC_PLATFORMS 8 + bool "Platform support for CZ.NIC's Turris hardware" 9 + help 10 + Say Y here to be able to choose driver support for CZ.NIC's Turris 11 + devices. This option alone does not add any kernel code. 12 + 13 + if CZNIC_PLATFORMS 14 + 15 + config TURRIS_OMNIA_MCU 16 + tristate "Turris Omnia MCU driver" 17 + depends on MACH_ARMADA_38X || COMPILE_TEST 18 + depends on I2C 19 + help 20 + Say Y here to add support for the features implemented by the 21 + microcontroller on the CZ.NIC's Turris Omnia SOHO router. 22 + To compile this driver as a module, choose M here; the module will be 23 + called turris-omnia-mcu. 24 + 25 + endif # CZNIC_PLATFORMS
+4
drivers/platform/cznic/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + 3 + obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o 4 + turris-omnia-mcu-y := turris-omnia-mcu-base.o
+394
drivers/platform/cznic/turris-omnia-mcu-base.c
··· 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 + NULL 201 + }; 202 + 203 + static void omnia_mcu_print_version_hash(struct omnia_mcu *mcu, bool bootloader) 204 + { 205 + const char *type = bootloader ? "bootloader" : "application"; 206 + struct device *dev = &mcu->client->dev; 207 + char version[OMNIA_FW_VERSION_HEX_LEN]; 208 + int err; 209 + 210 + err = omnia_get_version_hash(mcu, bootloader, version); 211 + if (err) { 212 + dev_err(dev, "Cannot read MCU %s firmware version: %d\n", 213 + type, err); 214 + return; 215 + } 216 + 217 + dev_info(dev, "MCU %s firmware version hash: %s\n", type, version); 218 + } 219 + 220 + static const char *omnia_status_to_mcu_type(u16 status) 221 + { 222 + switch (status & OMNIA_STS_MCU_TYPE_MASK) { 223 + case OMNIA_STS_MCU_TYPE_STM32: 224 + return "STM32"; 225 + case OMNIA_STS_MCU_TYPE_GD32: 226 + return "GD32"; 227 + case OMNIA_STS_MCU_TYPE_MKL: 228 + return "MKL"; 229 + default: 230 + return "unknown"; 231 + } 232 + } 233 + 234 + static void omnia_info_missing_feature(struct device *dev, const char *feature) 235 + { 236 + dev_info(dev, 237 + "Your board's MCU firmware does not support the %s feature.\n", 238 + feature); 239 + } 240 + 241 + static int omnia_mcu_read_features(struct omnia_mcu *mcu) 242 + { 243 + static const struct { 244 + u16 mask; 245 + const char *name; 246 + } features[] = { 247 + #define _DEF_FEAT(_n, _m) { OMNIA_FEAT_ ## _n, _m } 248 + _DEF_FEAT(EXT_CMDS, "extended control and status"), 249 + _DEF_FEAT(WDT_PING, "watchdog pinging"), 250 + _DEF_FEAT(LED_STATE_EXT_MASK, "peripheral LED pins reading"), 251 + _DEF_FEAT(NEW_INT_API, "new interrupt API"), 252 + _DEF_FEAT(POWEROFF_WAKEUP, "poweroff and wakeup"), 253 + _DEF_FEAT(TRNG, "true random number generator"), 254 + #undef _DEF_FEAT 255 + }; 256 + struct i2c_client *client = mcu->client; 257 + struct device *dev = &client->dev; 258 + bool suggest_fw_upgrade = false; 259 + u16 status; 260 + int err; 261 + 262 + /* status word holds MCU type, which we need below */ 263 + err = omnia_cmd_read_u16(client, OMNIA_CMD_GET_STATUS_WORD, &status); 264 + if (err) 265 + return err; 266 + 267 + /* 268 + * Check whether MCU firmware supports the OMNIA_CMD_GET_FEATURES 269 + * command. 270 + */ 271 + if (status & OMNIA_STS_FEATURES_SUPPORTED) { 272 + /* try read 32-bit features */ 273 + err = omnia_cmd_read_u32(client, OMNIA_CMD_GET_FEATURES, 274 + &mcu->features); 275 + if (err) { 276 + /* try read 16-bit features */ 277 + u16 features16; 278 + 279 + err = omnia_cmd_read_u16(client, OMNIA_CMD_GET_FEATURES, 280 + &features16); 281 + if (err) 282 + return err; 283 + 284 + mcu->features = features16; 285 + } else { 286 + if (mcu->features & OMNIA_FEAT_FROM_BIT_16_INVALID) 287 + mcu->features &= GENMASK(15, 0); 288 + } 289 + } else { 290 + dev_info(dev, 291 + "Your board's MCU firmware does not support feature reading.\n"); 292 + suggest_fw_upgrade = true; 293 + } 294 + 295 + mcu->type = omnia_status_to_mcu_type(status); 296 + dev_info(dev, "MCU type %s%s\n", mcu->type, 297 + (mcu->features & OMNIA_FEAT_PERIPH_MCU) ? 298 + ", with peripheral resets wired" : ""); 299 + 300 + omnia_mcu_print_version_hash(mcu, true); 301 + 302 + if (mcu->features & OMNIA_FEAT_BOOTLOADER) 303 + dev_warn(dev, 304 + "MCU is running bootloader firmware. Was firmware upgrade interrupted?\n"); 305 + else 306 + omnia_mcu_print_version_hash(mcu, false); 307 + 308 + for (unsigned int i = 0; i < ARRAY_SIZE(features); i++) { 309 + if (mcu->features & features[i].mask) 310 + continue; 311 + 312 + omnia_info_missing_feature(dev, features[i].name); 313 + suggest_fw_upgrade = true; 314 + } 315 + 316 + if (suggest_fw_upgrade) 317 + dev_info(dev, 318 + "Consider upgrading MCU firmware with the omnia-mcutool utility.\n"); 319 + 320 + return 0; 321 + } 322 + 323 + static int omnia_mcu_read_board_info(struct omnia_mcu *mcu) 324 + { 325 + u8 reply[1 + OMNIA_BOARD_INFO_LEN]; 326 + int err; 327 + 328 + err = omnia_cmd_read(mcu->client, OMNIA_CMD_BOARD_INFO_GET, reply, 329 + sizeof(reply)); 330 + if (err) 331 + return err; 332 + 333 + if (reply[0] != OMNIA_BOARD_INFO_LEN) 334 + return -EIO; 335 + 336 + mcu->board_serial_number = get_unaligned_le64(&reply[1]); 337 + 338 + /* we can't use ether_addr_copy() because reply is not u16-aligned */ 339 + memcpy(mcu->board_first_mac, &reply[9], sizeof(mcu->board_first_mac)); 340 + 341 + mcu->board_revision = reply[15]; 342 + 343 + return 0; 344 + } 345 + 346 + static int omnia_mcu_probe(struct i2c_client *client) 347 + { 348 + struct device *dev = &client->dev; 349 + struct omnia_mcu *mcu; 350 + int err; 351 + 352 + if (!client->irq) 353 + return dev_err_probe(dev, -EINVAL, "IRQ resource not found\n"); 354 + 355 + mcu = devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL); 356 + if (!mcu) 357 + return -ENOMEM; 358 + 359 + mcu->client = client; 360 + i2c_set_clientdata(client, mcu); 361 + 362 + err = omnia_mcu_read_features(mcu); 363 + if (err) 364 + return dev_err_probe(dev, err, 365 + "Cannot determine MCU supported features\n"); 366 + 367 + if (mcu->features & OMNIA_FEAT_BOARD_INFO) { 368 + err = omnia_mcu_read_board_info(mcu); 369 + if (err) 370 + return dev_err_probe(dev, err, 371 + "Cannot read board info\n"); 372 + } 373 + 374 + return 0; 375 + } 376 + 377 + static const struct of_device_id of_omnia_mcu_match[] = { 378 + { .compatible = "cznic,turris-omnia-mcu" }, 379 + {} 380 + }; 381 + 382 + static struct i2c_driver omnia_mcu_driver = { 383 + .probe = omnia_mcu_probe, 384 + .driver = { 385 + .name = "turris-omnia-mcu", 386 + .of_match_table = of_omnia_mcu_match, 387 + .dev_groups = omnia_mcu_groups, 388 + }, 389 + }; 390 + module_i2c_driver(omnia_mcu_driver); 391 + 392 + MODULE_AUTHOR("Marek Behun <kabel@kernel.org>"); 393 + MODULE_DESCRIPTION("CZ.NIC's Turris Omnia MCU"); 394 + MODULE_LICENSE("GPL");
+74
drivers/platform/cznic/turris-omnia-mcu.h
··· 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 + #ifndef __TURRIS_OMNIA_MCU_H 9 + #define __TURRIS_OMNIA_MCU_H 10 + 11 + #include <linux/if_ether.h> 12 + #include <linux/types.h> 13 + #include <asm/byteorder.h> 14 + 15 + struct i2c_client; 16 + 17 + struct omnia_mcu { 18 + struct i2c_client *client; 19 + const char *type; 20 + u32 features; 21 + 22 + /* board information */ 23 + u64 board_serial_number; 24 + u8 board_first_mac[ETH_ALEN]; 25 + u8 board_revision; 26 + }; 27 + 28 + int omnia_cmd_write_read(const struct i2c_client *client, 29 + void *cmd, unsigned int cmd_len, 30 + void *reply, unsigned int reply_len); 31 + 32 + static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd, 33 + void *reply, unsigned int len) 34 + { 35 + return omnia_cmd_write_read(client, &cmd, 1, reply, len); 36 + } 37 + 38 + static inline int omnia_cmd_read_u32(const struct i2c_client *client, u8 cmd, 39 + u32 *dst) 40 + { 41 + __le32 reply; 42 + int err; 43 + 44 + err = omnia_cmd_read(client, cmd, &reply, sizeof(reply)); 45 + if (err) 46 + return err; 47 + 48 + *dst = le32_to_cpu(reply); 49 + 50 + return 0; 51 + } 52 + 53 + static inline int omnia_cmd_read_u16(const struct i2c_client *client, u8 cmd, 54 + u16 *dst) 55 + { 56 + __le16 reply; 57 + int err; 58 + 59 + err = omnia_cmd_read(client, cmd, &reply, sizeof(reply)); 60 + if (err) 61 + return err; 62 + 63 + *dst = le16_to_cpu(reply); 64 + 65 + return 0; 66 + } 67 + 68 + static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd, 69 + u8 *reply) 70 + { 71 + return omnia_cmd_read(client, cmd, reply, sizeof(*reply)); 72 + } 73 + 74 + #endif /* __TURRIS_OMNIA_MCU_H */
+249
include/linux/turris-omnia-mcu-interface.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * CZ.NIC's Turris Omnia MCU I2C interface commands definitions 4 + * 5 + * 2024 by Marek Behún <kabel@kernel.org> 6 + */ 7 + 8 + #ifndef __TURRIS_OMNIA_MCU_INTERFACE_H 9 + #define __TURRIS_OMNIA_MCU_INTERFACE_H 10 + 11 + #include <linux/bitfield.h> 12 + #include <linux/bits.h> 13 + 14 + enum omnia_commands_e { 15 + OMNIA_CMD_GET_STATUS_WORD = 0x01, /* slave sends status word back */ 16 + OMNIA_CMD_GENERAL_CONTROL = 0x02, 17 + OMNIA_CMD_LED_MODE = 0x03, /* default/user */ 18 + OMNIA_CMD_LED_STATE = 0x04, /* LED on/off */ 19 + OMNIA_CMD_LED_COLOR = 0x05, /* LED number + RED + GREEN + BLUE */ 20 + OMNIA_CMD_USER_VOLTAGE = 0x06, 21 + OMNIA_CMD_SET_BRIGHTNESS = 0x07, 22 + OMNIA_CMD_GET_BRIGHTNESS = 0x08, 23 + OMNIA_CMD_GET_RESET = 0x09, 24 + OMNIA_CMD_GET_FW_VERSION_APP = 0x0A, /* 20B git hash number */ 25 + OMNIA_CMD_SET_WATCHDOG_STATE = 0x0B, /* 0 - disable 26 + * 1 - enable / ping 27 + * after boot watchdog is started 28 + * with 2 minutes timeout 29 + */ 30 + 31 + /* OMNIA_CMD_WATCHDOG_STATUS = 0x0C, not implemented anymore */ 32 + 33 + OMNIA_CMD_GET_WATCHDOG_STATE = 0x0D, 34 + OMNIA_CMD_GET_FW_VERSION_BOOT = 0x0E, /* 20B Git hash number */ 35 + OMNIA_CMD_GET_FW_CHECKSUM = 0x0F, /* 4B length, 4B checksum */ 36 + 37 + /* available if FEATURES_SUPPORTED bit set in status word */ 38 + OMNIA_CMD_GET_FEATURES = 0x10, 39 + 40 + /* available if EXT_CMD bit set in features */ 41 + OMNIA_CMD_GET_EXT_STATUS_DWORD = 0x11, 42 + OMNIA_CMD_EXT_CONTROL = 0x12, 43 + OMNIA_CMD_GET_EXT_CONTROL_STATUS = 0x13, 44 + 45 + /* available if NEW_INT_API bit set in features */ 46 + OMNIA_CMD_GET_INT_AND_CLEAR = 0x14, 47 + OMNIA_CMD_GET_INT_MASK = 0x15, 48 + OMNIA_CMD_SET_INT_MASK = 0x16, 49 + 50 + /* available if FLASHING bit set in features */ 51 + OMNIA_CMD_FLASH = 0x19, 52 + 53 + /* available if WDT_PING bit set in features */ 54 + OMNIA_CMD_SET_WDT_TIMEOUT = 0x20, 55 + OMNIA_CMD_GET_WDT_TIMELEFT = 0x21, 56 + 57 + /* available if POWEROFF_WAKEUP bit set in features */ 58 + OMNIA_CMD_SET_WAKEUP = 0x22, 59 + OMNIA_CMD_GET_UPTIME_AND_WAKEUP = 0x23, 60 + OMNIA_CMD_POWER_OFF = 0x24, 61 + 62 + /* available if USB_OVC_PROT_SETTING bit set in features */ 63 + OMNIA_CMD_SET_USB_OVC_PROT = 0x25, 64 + OMNIA_CMD_GET_USB_OVC_PROT = 0x26, 65 + 66 + /* available if TRNG bit set in features */ 67 + OMNIA_CMD_TRNG_COLLECT_ENTROPY = 0x28, 68 + 69 + /* available if CRYPTO bit set in features */ 70 + OMNIA_CMD_CRYPTO_GET_PUBLIC_KEY = 0x29, 71 + OMNIA_CMD_CRYPTO_SIGN_MESSAGE = 0x2A, 72 + OMNIA_CMD_CRYPTO_COLLECT_SIGNATURE = 0x2B, 73 + 74 + /* available if BOARD_INFO it set in features */ 75 + OMNIA_CMD_BOARD_INFO_GET = 0x2C, 76 + OMNIA_CMD_BOARD_INFO_BURN = 0x2D, 77 + 78 + /* available only at address 0x2b (LED-controller) */ 79 + /* available only if LED_GAMMA_CORRECTION bit set in features */ 80 + OMNIA_CMD_SET_GAMMA_CORRECTION = 0x30, 81 + OMNIA_CMD_GET_GAMMA_CORRECTION = 0x31, 82 + 83 + /* available only at address 0x2b (LED-controller) */ 84 + /* available only if PER_LED_CORRECTION bit set in features */ 85 + /* available only if FROM_BIT_16_INVALID bit NOT set in features */ 86 + OMNIA_CMD_SET_LED_CORRECTIONS = 0x32, 87 + OMNIA_CMD_GET_LED_CORRECTIONS = 0x33, 88 + }; 89 + 90 + enum omnia_flashing_commands_e { 91 + OMNIA_FLASH_CMD_UNLOCK = 0x01, 92 + OMNIA_FLASH_CMD_SIZE_AND_CSUM = 0x02, 93 + OMNIA_FLASH_CMD_PROGRAM = 0x03, 94 + OMNIA_FLASH_CMD_RESET = 0x04, 95 + }; 96 + 97 + enum omnia_sts_word_e { 98 + OMNIA_STS_MCU_TYPE_MASK = GENMASK(1, 0), 99 + OMNIA_STS_MCU_TYPE_STM32 = FIELD_PREP_CONST(OMNIA_STS_MCU_TYPE_MASK, 0), 100 + OMNIA_STS_MCU_TYPE_GD32 = FIELD_PREP_CONST(OMNIA_STS_MCU_TYPE_MASK, 1), 101 + OMNIA_STS_MCU_TYPE_MKL = FIELD_PREP_CONST(OMNIA_STS_MCU_TYPE_MASK, 2), 102 + OMNIA_STS_FEATURES_SUPPORTED = BIT(2), 103 + OMNIA_STS_USER_REGULATOR_NOT_SUPPORTED = BIT(3), 104 + OMNIA_STS_CARD_DET = BIT(4), 105 + OMNIA_STS_MSATA_IND = BIT(5), 106 + OMNIA_STS_USB30_OVC = BIT(6), 107 + OMNIA_STS_USB31_OVC = BIT(7), 108 + OMNIA_STS_USB30_PWRON = BIT(8), 109 + OMNIA_STS_USB31_PWRON = BIT(9), 110 + OMNIA_STS_ENABLE_4V5 = BIT(10), 111 + OMNIA_STS_BUTTON_MODE = BIT(11), 112 + OMNIA_STS_BUTTON_PRESSED = BIT(12), 113 + OMNIA_STS_BUTTON_COUNTER_MASK = GENMASK(15, 13), 114 + }; 115 + 116 + enum omnia_ctl_byte_e { 117 + OMNIA_CTL_LIGHT_RST = BIT(0), 118 + OMNIA_CTL_HARD_RST = BIT(1), 119 + /* BIT(2) is currently reserved */ 120 + OMNIA_CTL_USB30_PWRON = BIT(3), 121 + OMNIA_CTL_USB31_PWRON = BIT(4), 122 + OMNIA_CTL_ENABLE_4V5 = BIT(5), 123 + OMNIA_CTL_BUTTON_MODE = BIT(6), 124 + OMNIA_CTL_BOOTLOADER = BIT(7), 125 + }; 126 + 127 + enum omnia_features_e { 128 + OMNIA_FEAT_PERIPH_MCU = BIT(0), 129 + OMNIA_FEAT_EXT_CMDS = BIT(1), 130 + OMNIA_FEAT_WDT_PING = BIT(2), 131 + OMNIA_FEAT_LED_STATE_EXT_MASK = GENMASK(4, 3), 132 + OMNIA_FEAT_LED_STATE_EXT = FIELD_PREP_CONST(OMNIA_FEAT_LED_STATE_EXT_MASK, 1), 133 + OMNIA_FEAT_LED_STATE_EXT_V32 = FIELD_PREP_CONST(OMNIA_FEAT_LED_STATE_EXT_MASK, 2), 134 + OMNIA_FEAT_LED_GAMMA_CORRECTION = BIT(5), 135 + OMNIA_FEAT_NEW_INT_API = BIT(6), 136 + OMNIA_FEAT_BOOTLOADER = BIT(7), 137 + OMNIA_FEAT_FLASHING = BIT(8), 138 + OMNIA_FEAT_NEW_MESSAGE_API = BIT(9), 139 + OMNIA_FEAT_BRIGHTNESS_INT = BIT(10), 140 + OMNIA_FEAT_POWEROFF_WAKEUP = BIT(11), 141 + OMNIA_FEAT_CAN_OLD_MESSAGE_API = BIT(12), 142 + OMNIA_FEAT_TRNG = BIT(13), 143 + OMNIA_FEAT_CRYPTO = BIT(14), 144 + OMNIA_FEAT_BOARD_INFO = BIT(15), 145 + 146 + /* 147 + * Orginally the features command replied only 16 bits. If more were 148 + * read, either the I2C transaction failed or 0xff bytes were sent. 149 + * Therefore to consider bits 16 - 31 valid, one bit (20) was reserved 150 + * to be zero. 151 + */ 152 + 153 + /* Bits 16 - 19 correspond to bits 0 - 3 of status word */ 154 + OMNIA_FEAT_MCU_TYPE_MASK = GENMASK(17, 16), 155 + OMNIA_FEAT_MCU_TYPE_STM32 = FIELD_PREP_CONST(OMNIA_FEAT_MCU_TYPE_MASK, 0), 156 + OMNIA_FEAT_MCU_TYPE_GD32 = FIELD_PREP_CONST(OMNIA_FEAT_MCU_TYPE_MASK, 1), 157 + OMNIA_FEAT_MCU_TYPE_MKL = FIELD_PREP_CONST(OMNIA_FEAT_MCU_TYPE_MASK, 2), 158 + OMNIA_FEAT_FEATURES_SUPPORTED = BIT(18), 159 + OMNIA_FEAT_USER_REGULATOR_NOT_SUPPORTED = BIT(19), 160 + 161 + /* must not be set */ 162 + OMNIA_FEAT_FROM_BIT_16_INVALID = BIT(20), 163 + 164 + OMNIA_FEAT_PER_LED_CORRECTION = BIT(21), 165 + OMNIA_FEAT_USB_OVC_PROT_SETTING = BIT(22), 166 + }; 167 + 168 + enum omnia_ext_sts_dword_e { 169 + OMNIA_EXT_STS_SFP_nDET = BIT(0), 170 + OMNIA_EXT_STS_LED_STATES_MASK = GENMASK(31, 12), 171 + OMNIA_EXT_STS_WLAN0_MSATA_LED = BIT(12), 172 + OMNIA_EXT_STS_WLAN1_LED = BIT(13), 173 + OMNIA_EXT_STS_WLAN2_LED = BIT(14), 174 + OMNIA_EXT_STS_WPAN0_LED = BIT(15), 175 + OMNIA_EXT_STS_WPAN1_LED = BIT(16), 176 + OMNIA_EXT_STS_WPAN2_LED = BIT(17), 177 + OMNIA_EXT_STS_WAN_LED0 = BIT(18), 178 + OMNIA_EXT_STS_WAN_LED1 = BIT(19), 179 + OMNIA_EXT_STS_LAN0_LED0 = BIT(20), 180 + OMNIA_EXT_STS_LAN0_LED1 = BIT(21), 181 + OMNIA_EXT_STS_LAN1_LED0 = BIT(22), 182 + OMNIA_EXT_STS_LAN1_LED1 = BIT(23), 183 + OMNIA_EXT_STS_LAN2_LED0 = BIT(24), 184 + OMNIA_EXT_STS_LAN2_LED1 = BIT(25), 185 + OMNIA_EXT_STS_LAN3_LED0 = BIT(26), 186 + OMNIA_EXT_STS_LAN3_LED1 = BIT(27), 187 + OMNIA_EXT_STS_LAN4_LED0 = BIT(28), 188 + OMNIA_EXT_STS_LAN4_LED1 = BIT(29), 189 + OMNIA_EXT_STS_LAN5_LED0 = BIT(30), 190 + OMNIA_EXT_STS_LAN5_LED1 = BIT(31), 191 + }; 192 + 193 + enum omnia_ext_ctl_e { 194 + OMNIA_EXT_CTL_nRES_MMC = BIT(0), 195 + OMNIA_EXT_CTL_nRES_LAN = BIT(1), 196 + OMNIA_EXT_CTL_nRES_PHY = BIT(2), 197 + OMNIA_EXT_CTL_nPERST0 = BIT(3), 198 + OMNIA_EXT_CTL_nPERST1 = BIT(4), 199 + OMNIA_EXT_CTL_nPERST2 = BIT(5), 200 + OMNIA_EXT_CTL_PHY_SFP = BIT(6), 201 + OMNIA_EXT_CTL_PHY_SFP_AUTO = BIT(7), 202 + OMNIA_EXT_CTL_nVHV_CTRL = BIT(8), 203 + }; 204 + 205 + enum omnia_int_e { 206 + OMNIA_INT_CARD_DET = BIT(0), 207 + OMNIA_INT_MSATA_IND = BIT(1), 208 + OMNIA_INT_USB30_OVC = BIT(2), 209 + OMNIA_INT_USB31_OVC = BIT(3), 210 + OMNIA_INT_BUTTON_PRESSED = BIT(4), 211 + OMNIA_INT_SFP_nDET = BIT(5), 212 + OMNIA_INT_BRIGHTNESS_CHANGED = BIT(6), 213 + OMNIA_INT_TRNG = BIT(7), 214 + OMNIA_INT_MESSAGE_SIGNED = BIT(8), 215 + 216 + OMNIA_INT_LED_STATES_MASK = GENMASK(31, 12), 217 + OMNIA_INT_WLAN0_MSATA_LED = BIT(12), 218 + OMNIA_INT_WLAN1_LED = BIT(13), 219 + OMNIA_INT_WLAN2_LED = BIT(14), 220 + OMNIA_INT_WPAN0_LED = BIT(15), 221 + OMNIA_INT_WPAN1_LED = BIT(16), 222 + OMNIA_INT_WPAN2_LED = BIT(17), 223 + OMNIA_INT_WAN_LED0 = BIT(18), 224 + OMNIA_INT_WAN_LED1 = BIT(19), 225 + OMNIA_INT_LAN0_LED0 = BIT(20), 226 + OMNIA_INT_LAN0_LED1 = BIT(21), 227 + OMNIA_INT_LAN1_LED0 = BIT(22), 228 + OMNIA_INT_LAN1_LED1 = BIT(23), 229 + OMNIA_INT_LAN2_LED0 = BIT(24), 230 + OMNIA_INT_LAN2_LED1 = BIT(25), 231 + OMNIA_INT_LAN3_LED0 = BIT(26), 232 + OMNIA_INT_LAN3_LED1 = BIT(27), 233 + OMNIA_INT_LAN4_LED0 = BIT(28), 234 + OMNIA_INT_LAN4_LED1 = BIT(29), 235 + OMNIA_INT_LAN5_LED0 = BIT(30), 236 + OMNIA_INT_LAN5_LED1 = BIT(31), 237 + }; 238 + 239 + enum omnia_cmd_poweroff_e { 240 + OMNIA_CMD_POWER_OFF_POWERON_BUTTON = BIT(0), 241 + OMNIA_CMD_POWER_OFF_MAGIC = 0xdead, 242 + }; 243 + 244 + enum omnia_cmd_usb_ovc_prot_e { 245 + OMNIA_CMD_xET_USB_OVC_PROT_PORT_MASK = GENMASK(3, 0), 246 + OMNIA_CMD_xET_USB_OVC_PROT_ENABLE = BIT(4), 247 + }; 248 + 249 + #endif /* __TURRIS_OMNIA_MCU_INTERFACE_H */