* [PATCH v5 00/11] Turris Omnia MCU driver
@ 2024-03-23 16:43 Marek Behún
2024-03-23 16:43 ` [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU Marek Behún
2024-03-23 16:43 ` [PATCH v5 05/11] platform: cznic: turris-omnia-mcu: Add support for MCU watchdog Marek Behún
0 siblings, 2 replies; 8+ messages in thread
From: Marek Behún @ 2024-03-23 16:43 UTC (permalink / raw)
To: Arnd Bergmann, Gregory CLEMENT, soc, arm, Alessandro Zummo,
Alexandre Belloni, Andy Shevchenko, Bartosz Golaszewski,
devicetree, Greg Kroah-Hartman, Guenter Roeck, Herbert Xu,
Krzysztof Kozlowski, Linus Walleij, linux-crypto, linux-gpio,
linux-rtc, linux-watchdog, Rob Herring, Wim Van Sebroeck,
Hans de Goede, Matti Vaittinen
Cc: Marek Behún
Hello Andy, Linus, Arnd, Gregory, and others,
I am sending v5 of the series adding Turris Omnia MCU driver.
See the cover letters for v1, v2, v3 and v4:
https://patchwork.kernel.org/project/linux-soc/cover/20230823161012.6986-1-kabel@kernel.org/
https://patchwork.kernel.org/project/linux-soc/cover/20230919103815.16818-1-kabel@kernel.org/
https://patchwork.kernel.org/project/linux-soc/cover/20231023143130.11602-1-kabel@kernel.org/
https://patchwork.kernel.org/project/linux-soc/cover/20231026161803.16750-1-kabel@kernel.org/
Changes since v4:
- added new patches
06/11 devm-helpers: Add resource managed version of irq_create_mapping()
07/11 platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG
08/11 devm-helpers: Add resource managed version of debugfs directory create
function
09/11 platform: cznic: turris-omnia-mcu: Add support for digital message
signing via debugfs
- for changes specific to patches which were also sent in previous versions see
the notes in those patches
Marek Behún (11):
dt-bindings: arm: add cznic,turris-omnia-mcu binding
platform: cznic: Add preliminary support for Turris Omnia MCU
platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs
platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup
platform: cznic: turris-omnia-mcu: Add support for MCU watchdog
devm-helpers: Add resource managed version of irq_create_mapping()
platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG
devm-helpers: Add resource managed version of debugfs directory create
function
platform: cznic: turris-omnia-mcu: Add support for digital message
signing via debugfs
ARM: dts: turris-omnia: Add MCU system-controller node
ARM: dts: turris-omnia: Add GPIO key node for front button
.../ABI/testing/debugfs-turris-omnia-mcu | 13 +
.../sysfs-bus-i2c-devices-turris-omnia-mcu | 126 ++
.../bindings/arm/cznic,turris-omnia-mcu.yaml | 86 ++
MAINTAINERS | 5 +
.../dts/marvell/armada-385-turris-omnia.dts | 35 +-
drivers/crypto/caam/ctrl.c | 16 +-
drivers/crypto/caam/jr.c | 8 +-
drivers/gpio/gpio-mockup.c | 11 +-
drivers/gpu/drm/bridge/ti-sn65dsi86.c | 13 +-
drivers/hwmon/hp-wmi-sensors.c | 15 +-
drivers/hwmon/mr75203.c | 15 +-
drivers/hwmon/pmbus/pmbus_core.c | 16 +-
drivers/platform/Kconfig | 2 +
drivers/platform/Makefile | 1 +
drivers/platform/cznic/Kconfig | 51 +
drivers/platform/cznic/Makefile | 10 +
.../platform/cznic/turris-omnia-mcu-base.c | 406 +++++++
.../platform/cznic/turris-omnia-mcu-debugfs.c | 216 ++++
.../platform/cznic/turris-omnia-mcu-gpio.c | 1056 +++++++++++++++++
.../cznic/turris-omnia-mcu-sys-off-wakeup.c | 258 ++++
.../platform/cznic/turris-omnia-mcu-trng.c | 89 ++
.../cznic/turris-omnia-mcu-watchdog.c | 122 ++
drivers/platform/cznic/turris-omnia-mcu.h | 214 ++++
include/linux/devm-helpers.h | 94 ++
include/linux/turris-omnia-mcu-interface.h | 238 ++++
25 files changed, 3044 insertions(+), 72 deletions(-)
create mode 100644 Documentation/ABI/testing/debugfs-turris-omnia-mcu
create mode 100644 Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
create mode 100644 Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml
create mode 100644 drivers/platform/cznic/Kconfig
create mode 100644 drivers/platform/cznic/Makefile
create mode 100644 drivers/platform/cznic/turris-omnia-mcu-base.c
create mode 100644 drivers/platform/cznic/turris-omnia-mcu-debugfs.c
create mode 100644 drivers/platform/cznic/turris-omnia-mcu-gpio.c
create mode 100644 drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c
create mode 100644 drivers/platform/cznic/turris-omnia-mcu-trng.c
create mode 100644 drivers/platform/cznic/turris-omnia-mcu-watchdog.c
create mode 100644 drivers/platform/cznic/turris-omnia-mcu.h
create mode 100644 include/linux/turris-omnia-mcu-interface.h
--
2.43.2
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU
2024-03-23 16:43 [PATCH v5 00/11] Turris Omnia MCU driver Marek Behún
@ 2024-03-23 16:43 ` Marek Behún
2024-03-24 11:01 ` Andy Shevchenko
2024-03-23 16:43 ` [PATCH v5 05/11] platform: cznic: turris-omnia-mcu: Add support for MCU watchdog Marek Behún
1 sibling, 1 reply; 8+ messages in thread
From: Marek Behún @ 2024-03-23 16:43 UTC (permalink / raw)
To: Arnd Bergmann, Gregory CLEMENT, soc, arm, Linus Walleij,
Bartosz Golaszewski, Andy Shevchenko, linux-gpio,
Alessandro Zummo, Alexandre Belloni, linux-rtc, Wim Van Sebroeck,
Guenter Roeck, linux-watchdog
Cc: Marek Behún
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>
---
Changes since v4:
- added board information reading code and new sysfs files: board_revision,
first_mac_address and serial_number. These are present if the MCU firmware
supports the FEAT_BOARD_INFO feature, which is a new feature implemented
for boards where MCU is also responsible for board information
---
.../sysfs-bus-i2c-devices-turris-omnia-mcu | 81 ++++
MAINTAINERS | 3 +
drivers/platform/Kconfig | 2 +
drivers/platform/Makefile | 1 +
drivers/platform/cznic/Kconfig | 26 ++
drivers/platform/cznic/Makefile | 4 +
.../platform/cznic/turris-omnia-mcu-base.c | 349 ++++++++++++++++++
drivers/platform/cznic/turris-omnia-mcu.h | 71 ++++
include/linux/turris-omnia-mcu-interface.h | 238 ++++++++++++
9 files changed, 775 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
create mode 100644 drivers/platform/cznic/Kconfig
create mode 100644 drivers/platform/cznic/Makefile
create mode 100644 drivers/platform/cznic/turris-omnia-mcu-base.c
create mode 100644 drivers/platform/cznic/turris-omnia-mcu.h
create mode 100644 include/linux/turris-omnia-mcu-interface.h
diff --git a/Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu b/Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
new file mode 100644
index 000000000000..ff5e7cb00206
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
@@ -0,0 +1,81 @@
+What: /sys/bus/i2c/devices/<mcu_device>/board_revision
+Date: July 2024
+KernelVersion: 6.10
+Contact: Marek Behún <kabel@kernel.org>
+Description: (RO) Contains board revision number.
+
+ Only available if board information is burned in the MCU (older
+ revisions have board information burned in the ATSHA204-A chip).
+
+ Format: %u.
+
+What: /sys/bus/i2c/devices/<mcu_device>/first_mac_address
+Date: July 2024
+KernelVersion: 6.10
+Contact: Marek Behún <kabel@kernel.org>
+Description: (RO) Contains device first MAC address. Each Turris Omnia is
+ allocated 3 MAC addresses. The two additional addresses are
+ computed from the first one by incrementing it.
+
+ Only available if board information is burned in the MCU (older
+ revisions have board information burned in the ATSHA204-A chip).
+
+ Format: %pM.
+
+What: /sys/bus/i2c/devices/<mcu_device>/fw_features
+Date: July 2024
+KernelVersion: 6.10
+Contact: Marek Behún <kabel@kernel.org>
+Description: (RO) Newer versions of the microcontroller firmware report the
+ features they support. These can be read from this file. If the
+ MCU firmware is too old, this file reads 0x0.
+
+ Format: 0x%x.
+
+What: /sys/bus/i2c/devices/<mcu_device>/fw_version_hash_application
+Date: July 2024
+KernelVersion: 6.10
+Contact: Marek Behún <kabel@kernel.org>
+Description: (RO) Contains the version hash (commit hash) of the application
+ part of the microcontroller firmware.
+
+ Format: %s.
+
+What: /sys/bus/i2c/devices/<mcu_device>/fw_version_hash_bootloader
+Date: July 2024
+KernelVersion: 6.10
+Contact: Marek Behún <kabel@kernel.org>
+Description: (RO) Contains the version hash (commit hash) of the bootloader
+ part of the microcontroller firmware.
+
+ Format: %s.
+
+What: /sys/bus/i2c/devices/<mcu_device>/mcu_type
+Date: July 2024
+KernelVersion: 6.10
+Contact: Marek Behún <kabel@kernel.org>
+Description: (RO) Contains the microcontroller type (STM32, GD32, MKL).
+
+ Format: %s.
+
+What: /sys/bus/i2c/devices/<mcu_device>/reset_selector
+Date: July 2024
+KernelVersion: 6.10
+Contact: Marek Behún <kabel@kernel.org>
+Description: (RO) Contains the selected factory reset level, determined by
+ how long the rear reset button was held by the user during board
+ reset.
+
+ Format: %i.
+
+What: /sys/bus/i2c/devices/<mcu_device>/serial_number
+Date: July 2024
+KernelVersion: 6.10
+Contact: Marek Behún <kabel@kernel.org>
+Description: (RO) Contains the 64 bit long board serial number in hexadecimal
+ format.
+
+ Only available if board information is burned in the MCU (older
+ revisions have board information burned in the ATSHA204-A chip).
+
+ Format: %016X.
diff --git a/MAINTAINERS b/MAINTAINERS
index 89edfc2b875b..529e16d386e8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2139,6 +2139,7 @@ M: Marek Behún <kabel@kernel.org>
S: Maintained
W: https://www.turris.cz/
F: Documentation/ABI/testing/debugfs-moxtet
+F: Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu
F: Documentation/ABI/testing/sysfs-bus-moxtet-devices
F: Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm
F: Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml
@@ -2152,10 +2153,12 @@ F: drivers/firmware/turris-mox-rwtm.c
F: drivers/gpio/gpio-moxtet.c
F: drivers/leds/leds-turris-omnia.c
F: drivers/mailbox/armada-37xx-rwtm-mailbox.c
+F: drivers/platform/cznic/
F: drivers/watchdog/armada_37xx_wdt.c
F: include/dt-bindings/bus/moxtet.h
F: include/linux/armada-37xx-rwtm-mailbox.h
F: include/linux/moxtet.h
+F: include/linux/turris-omnia-mcu-interface.h
ARM/FARADAY FA526 PORT
M: Hans Ulli Kroll <ulli.kroll@googlemail.com>
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig
index 868b20361769..fef907a94001 100644
--- a/drivers/platform/Kconfig
+++ b/drivers/platform/Kconfig
@@ -7,6 +7,8 @@ source "drivers/platform/goldfish/Kconfig"
source "drivers/platform/chrome/Kconfig"
+source "drivers/platform/cznic/Kconfig"
+
source "drivers/platform/mellanox/Kconfig"
source "drivers/platform/olpc/Kconfig"
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile
index 41640172975a..8bf189264374 100644
--- a/drivers/platform/Makefile
+++ b/drivers/platform/Makefile
@@ -10,4 +10,5 @@ obj-$(CONFIG_MIPS) += mips/
obj-$(CONFIG_OLPC_EC) += olpc/
obj-$(CONFIG_GOLDFISH) += goldfish/
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
+obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/
obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
diff --git a/drivers/platform/cznic/Kconfig b/drivers/platform/cznic/Kconfig
new file mode 100644
index 000000000000..f8560ff9c1af
--- /dev/null
+++ b/drivers/platform/cznic/Kconfig
@@ -0,0 +1,26 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.rst.
+#
+
+menuconfig CZNIC_PLATFORMS
+ bool "Platform support for CZ.NIC's Turris hardware"
+ depends on MACH_ARMADA_38X || COMPILE_TEST
+ help
+ Say Y here to be able to choose driver support for CZ.NIC's Turris
+ devices. This option alone does not add any kernel code.
+
+if CZNIC_PLATFORMS
+
+config TURRIS_OMNIA_MCU
+ tristate "Turris Omnia MCU driver"
+ depends on MACH_ARMADA_38X || COMPILE_TEST
+ depends on I2C
+ help
+ Say Y here to add support for the features implemented by the
+ microcontroller on the CZ.NIC's Turris Omnia SOHO router.
+ To compile this driver as a module, choose M here; the module will be
+ called turris-omnia-mcu.
+
+endif # CZNIC_PLATFORMS
diff --git a/drivers/platform/cznic/Makefile b/drivers/platform/cznic/Makefile
new file mode 100644
index 000000000000..4d0a9586538c
--- /dev/null
+++ b/drivers/platform/cznic/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o
+turris-omnia-mcu-objs := turris-omnia-mcu-base.o
diff --git a/drivers/platform/cznic/turris-omnia-mcu-base.c b/drivers/platform/cznic/turris-omnia-mcu-base.c
new file mode 100644
index 000000000000..27f08ce8f368
--- /dev/null
+++ b/drivers/platform/cznic/turris-omnia-mcu-base.c
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CZ.NIC's Turris Omnia MCU driver
+ *
+ * 2024 by Marek Behún <kabel@kernel.org>
+ */
+
+#include <linux/device.h>
+#include <linux/hex.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/turris-omnia-mcu-interface.h>
+#include <linux/types.h>
+#include <linux/sysfs.h>
+
+#include "turris-omnia-mcu.h"
+
+#define OMNIA_FW_VERSION_LEN 20
+#define OMNIA_FW_VERSION_HEX_LEN (2 * OMNIA_FW_VERSION_LEN + 1)
+#define OMNIA_BOARD_INFO_LEN 16
+
+static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader,
+ u8 version[static OMNIA_FW_VERSION_HEX_LEN])
+{
+ u8 reply[OMNIA_FW_VERSION_LEN];
+ int err;
+
+ err = omnia_cmd_read(mcu->client, bootloader ? CMD_GET_FW_VERSION_BOOT :
+ CMD_GET_FW_VERSION_APP,
+ reply, sizeof(reply));
+ if (err)
+ return err;
+
+ version[OMNIA_FW_VERSION_HEX_LEN - 1] = '\0';
+ bin2hex(version, reply, OMNIA_FW_VERSION_LEN);
+
+ return 0;
+}
+
+static ssize_t fw_version_hash_show(struct device *dev, char *buf,
+ bool bootloader)
+{
+ struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
+ u8 version[OMNIA_FW_VERSION_HEX_LEN];
+ int err;
+
+ err = omnia_get_version_hash(mcu, bootloader, version);
+ if (err)
+ return err;
+
+ return sysfs_emit(buf, "%s\n", version);
+}
+
+static ssize_t fw_version_hash_application_show(struct device *dev,
+ struct device_attribute *a,
+ char *buf)
+{
+ return fw_version_hash_show(dev, buf, false);
+}
+static DEVICE_ATTR_RO(fw_version_hash_application);
+
+static ssize_t fw_version_hash_bootloader_show(struct device *dev,
+ struct device_attribute *a,
+ char *buf)
+{
+ return fw_version_hash_show(dev, buf, true);
+}
+static DEVICE_ATTR_RO(fw_version_hash_bootloader);
+
+static ssize_t fw_features_show(struct device *dev, struct device_attribute *a,
+ char *buf)
+{
+ struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
+
+ return sysfs_emit(buf, "0x%x\n", mcu->features);
+}
+static DEVICE_ATTR_RO(fw_features);
+
+static ssize_t mcu_type_show(struct device *dev, struct device_attribute *a,
+ char *buf)
+{
+ struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
+
+ return sysfs_emit(buf, "%s\n", mcu->type);
+}
+static DEVICE_ATTR_RO(mcu_type);
+
+static ssize_t reset_selector_show(struct device *dev,
+ struct device_attribute *a, char *buf)
+{
+ int ret;
+
+ ret = omnia_cmd_read_u8(to_i2c_client(dev), CMD_GET_RESET);
+ if (ret < 0)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", ret);
+}
+static DEVICE_ATTR_RO(reset_selector);
+
+static ssize_t serial_number_show(struct device *dev,
+ struct device_attribute *a, char *buf)
+{
+ struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
+
+ return sysfs_emit(buf, "%016llX\n", mcu->board_serial_number);
+}
+static DEVICE_ATTR_RO(serial_number);
+
+static ssize_t first_mac_address_show(struct device *dev,
+ struct device_attribute *a, char *buf)
+{
+ struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
+
+ return sysfs_emit(buf, "%pM\n", mcu->board_first_mac);
+}
+static DEVICE_ATTR_RO(first_mac_address);
+
+static ssize_t board_revision_show(struct device *dev,
+ struct device_attribute *a, char *buf)
+{
+ struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
+
+ return sysfs_emit(buf, "%u\n", mcu->board_revision);
+}
+static DEVICE_ATTR_RO(board_revision);
+
+static struct attribute *omnia_mcu_base_attrs[] = {
+ &dev_attr_fw_version_hash_application.attr,
+ &dev_attr_fw_version_hash_bootloader.attr,
+ &dev_attr_fw_features.attr,
+ &dev_attr_mcu_type.attr,
+ &dev_attr_reset_selector.attr,
+ &dev_attr_serial_number.attr,
+ &dev_attr_first_mac_address.attr,
+ &dev_attr_board_revision.attr,
+ NULL
+};
+
+static umode_t omnia_mcu_base_attrs_visible(struct kobject *kobj,
+ struct attribute *a, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
+ umode_t mode = a->mode;
+
+ if ((a == &dev_attr_serial_number.attr ||
+ a == &dev_attr_first_mac_address.attr ||
+ a == &dev_attr_board_revision.attr) &&
+ !(mcu->features & FEAT_BOARD_INFO))
+ mode = 0;
+
+ return mode;
+}
+
+static const struct attribute_group omnia_mcu_base_group = {
+ .attrs = omnia_mcu_base_attrs,
+ .is_visible = omnia_mcu_base_attrs_visible,
+};
+
+static const struct attribute_group *omnia_mcu_groups[] = {
+ &omnia_mcu_base_group,
+ NULL
+};
+
+static void omnia_mcu_print_version_hash(struct omnia_mcu *mcu, bool bootloader)
+{
+ const char *type = bootloader ? "bootloader" : "application";
+ struct device *dev = &mcu->client->dev;
+ u8 version[OMNIA_FW_VERSION_HEX_LEN];
+ int err;
+
+ err = omnia_get_version_hash(mcu, bootloader, version);
+ if (err) {
+ dev_err(dev, "Cannot read MCU %s firmware version: %d\n", type,
+ err);
+ return;
+ }
+
+ dev_info(dev, "MCU %s firmware version hash: %s\n", type, version);
+}
+
+static const char *omnia_status_to_mcu_type(uint16_t status)
+{
+ switch (status & STS_MCU_TYPE_MASK) {
+ case STS_MCU_TYPE_STM32:
+ return "STM32";
+ case STS_MCU_TYPE_GD32:
+ return "GD32";
+ case STS_MCU_TYPE_MKL:
+ return "MKL";
+ default:
+ return "unknown";
+ }
+}
+
+static void omnia_info_missing_feature(struct device *dev, const char *feature)
+{
+ dev_info(dev,
+ "Your board's MCU firmware does not support the %s feature.\n",
+ feature);
+}
+
+static int omnia_mcu_read_features(struct omnia_mcu *mcu)
+{
+ static const struct {
+ uint16_t mask;
+ const char *name;
+ } features[] = {
+ { FEAT_EXT_CMDS, "extended control and status" },
+ { FEAT_WDT_PING, "watchdog pinging" },
+ { FEAT_LED_STATE_EXT_MASK, "peripheral LED pins reading" },
+ { FEAT_NEW_INT_API, "new interrupt API" },
+ { FEAT_POWEROFF_WAKEUP, "poweroff and wakeup" },
+ { FEAT_TRNG, "true random number generator" },
+ };
+ struct device *dev = &mcu->client->dev;
+ bool suggest_fw_upgrade = false;
+ int status;
+
+ /* status word holds MCU type, which we need below */
+ status = omnia_cmd_read_u16(mcu->client, CMD_GET_STATUS_WORD);
+ if (status < 0)
+ return status;
+
+ /* check whether MCU firmware supports the CMD_GET_FEAUTRES command */
+ if (status & STS_FEATURES_SUPPORTED) {
+ __le32 reply;
+ int ret;
+
+ /* try read 32-bit features */
+ ret = omnia_cmd_read(mcu->client, CMD_GET_FEATURES, &reply,
+ sizeof(reply));
+ if (ret) {
+ /* try read 16-bit features */
+ ret = omnia_cmd_read_u16(mcu->client, CMD_GET_FEATURES);
+ if (ret < 0)
+ return ret;
+
+ mcu->features = features;
+ } else {
+ mcu->features = le32_to_cpu(reply);
+
+ if (mcu->features & FEAT_FROM_BIT_16_INVALID)
+ mcu->features &= GENMASK(15, 0);
+ }
+ } else {
+ omnia_info_missing_feature(dev, "feature reading");
+ suggest_fw_upgrade = true;
+ }
+
+ mcu->type = omnia_status_to_mcu_type(status);
+ dev_info(dev, "MCU type %s%s\n", mcu->type,
+ (mcu->features & FEAT_PERIPH_MCU) ?
+ ", with peripheral resets wired" : "");
+
+ omnia_mcu_print_version_hash(mcu, true);
+
+ if (mcu->features & FEAT_BOOTLOADER)
+ dev_warn(dev,
+ "MCU is running bootloader firmware. Was firmware upgrade interrupted?\n");
+ else
+ omnia_mcu_print_version_hash(mcu, false);
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(features); i++) {
+ if (mcu->features & features[i].mask)
+ continue;
+
+ omnia_info_missing_feature(dev, features[i].name);
+ suggest_fw_upgrade = true;
+ }
+
+ if (suggest_fw_upgrade)
+ dev_info(dev,
+ "Consider upgrading MCU firmware with the omnia-mcutool utility.\n");
+
+ return 0;
+}
+
+static int omnia_mcu_read_board_info(struct omnia_mcu *mcu)
+{
+ u8 reply[1 + OMNIA_BOARD_INFO_LEN];
+ int err;
+
+ err = omnia_cmd_read(mcu->client, CMD_BOARD_INFO_GET, reply,
+ sizeof(reply));
+ if (err)
+ return err;
+
+ if (reply[0] != OMNIA_BOARD_INFO_LEN)
+ return -EIO;
+
+ mcu->board_serial_number = get_unaligned_le64(&reply[1]);
+ memcpy(mcu->board_first_mac, &reply[9], ETH_ALEN);
+ mcu->board_revision = reply[15];
+
+ return 0;
+}
+
+static int omnia_mcu_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct omnia_mcu *mcu;
+ int err;
+
+ if (!client->irq)
+ return dev_err_probe(dev, -EINVAL, "IRQ resource not found\n");
+
+ mcu = devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL);
+ if (!mcu)
+ return -ENOMEM;
+
+ mcu->client = client;
+ i2c_set_clientdata(client, mcu);
+
+ err = omnia_mcu_read_features(mcu);
+ if (err)
+ return dev_err_probe(dev, err,
+ "Cannot determine MCU supported features\n");
+
+ if (mcu->features & FEAT_BOARD_INFO) {
+ err = omnia_mcu_read_board_info(mcu);
+ if (err)
+ return dev_err_probe(dev, err,
+ "Cannot read board info\n");
+ }
+
+ return 0;
+}
+
+static const struct of_device_id of_omnia_mcu_match[] = {
+ { .compatible = "cznic,turris-omnia-mcu" },
+ {}
+};
+
+static struct i2c_driver omnia_mcu_driver = {
+ .probe = omnia_mcu_probe,
+ .driver = {
+ .name = "turris-omnia-mcu",
+ .of_match_table = of_omnia_mcu_match,
+ .dev_groups = omnia_mcu_groups,
+ },
+};
+
+module_i2c_driver(omnia_mcu_driver);
+
+MODULE_AUTHOR("Marek Behun <kabel@kernel.org>");
+MODULE_DESCRIPTION("CZ.NIC's Turris Omnia MCU");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/cznic/turris-omnia-mcu.h b/drivers/platform/cznic/turris-omnia-mcu.h
new file mode 100644
index 000000000000..0662626c6007
--- /dev/null
+++ b/drivers/platform/cznic/turris-omnia-mcu.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CZ.NIC's Turris Omnia MCU driver
+ *
+ * 2024 by Marek Behún <kabel@kernel.org>
+ */
+
+#ifndef __TURRIS_OMNIA_MCU_H
+#define __TURRIS_OMNIA_MCU_H
+
+#include <linux/i2c.h>
+#include <linux/if_ether.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+struct omnia_mcu {
+ struct i2c_client *client;
+ const char *type;
+ u32 features;
+
+ /* board information */
+ u64 board_serial_number;
+ u8 board_first_mac[ETH_ALEN];
+ u8 board_revision;
+};
+
+static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
+ void *reply, unsigned int len)
+{
+ struct i2c_msg msgs[2];
+ int ret;
+
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 1;
+ msgs[0].buf = &cmd;
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = len;
+ msgs[1].buf = reply;
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return ret;
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ return 0;
+}
+
+static inline int omnia_cmd_read_u16(const struct i2c_client *client, u8 cmd)
+{
+ __le16 reply;
+ int err;
+
+ err = omnia_cmd_read(client, cmd, &reply, sizeof(reply));
+
+ return err ?: le16_to_cpu(reply);
+}
+
+static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
+{
+ u8 reply;
+ int err;
+
+ err = omnia_cmd_read(client, cmd, &reply, sizeof(reply));
+
+ return err ?: reply;
+}
+
+#endif /* __TURRIS_OMNIA_MCU_H */
diff --git a/include/linux/turris-omnia-mcu-interface.h b/include/linux/turris-omnia-mcu-interface.h
new file mode 100644
index 000000000000..84bb47786147
--- /dev/null
+++ b/include/linux/turris-omnia-mcu-interface.h
@@ -0,0 +1,238 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CZ.NIC's Turris Omnia MCU I2C interface commands definitions
+ *
+ * 2023 by Marek Behún <kabel@kernel.org>
+ */
+
+#ifndef __TURRIS_OMNIA_MCU_INTERFACE_H
+#define __TURRIS_OMNIA_MCU_INTERFACE_H
+
+#include <linux/bits.h>
+
+enum omnia_commands_e {
+ CMD_GET_STATUS_WORD = 0x01, /* slave sends status word back */
+ CMD_GENERAL_CONTROL = 0x02,
+ CMD_LED_MODE = 0x03, /* default/user */
+ CMD_LED_STATE = 0x04, /* LED on/off */
+ CMD_LED_COLOR = 0x05, /* LED number + RED + GREEN + BLUE */
+ CMD_USER_VOLTAGE = 0x06,
+ CMD_SET_BRIGHTNESS = 0x07,
+ CMD_GET_BRIGHTNESS = 0x08,
+ CMD_GET_RESET = 0x09,
+ CMD_GET_FW_VERSION_APP = 0x0A, /* 20B git hash number */
+ CMD_SET_WATCHDOG_STATE = 0x0B, /* 0 - disable
+ * 1 - enable / ping
+ * after boot watchdog is started
+ * with 2 minutes timeout
+ */
+
+ /* CMD_WATCHDOG_STATUS = 0x0C, not implemented anymore */
+
+ CMD_GET_WATCHDOG_STATE = 0x0D,
+ CMD_GET_FW_VERSION_BOOT = 0x0E, /* 20B git hash number */
+ CMD_GET_FW_CHECKSUM = 0x0F, /* 4B length, 4B checksum */
+
+ /* available if FEATURES_SUPPORTED bit set in status word */
+ CMD_GET_FEATURES = 0x10,
+
+ /* available if EXT_CMD bit set in features */
+ CMD_GET_EXT_STATUS_DWORD = 0x11,
+ CMD_EXT_CONTROL = 0x12,
+ CMD_GET_EXT_CONTROL_STATUS = 0x13,
+
+ /* available if NEW_INT_API bit set in features */
+ CMD_GET_INT_AND_CLEAR = 0x14,
+ CMD_GET_INT_MASK = 0x15,
+ CMD_SET_INT_MASK = 0x16,
+
+ /* available if FLASHING bit set in features */
+ CMD_FLASH = 0x19,
+
+ /* available if WDT_PING bit set in features */
+ CMD_SET_WDT_TIMEOUT = 0x20,
+ CMD_GET_WDT_TIMELEFT = 0x21,
+
+ /* available if POWEROFF_WAKEUP bit set in features */
+ CMD_SET_WAKEUP = 0x22,
+ CMD_GET_UPTIME_AND_WAKEUP = 0x23,
+ CMD_POWER_OFF = 0x24,
+
+ /* available if TRNG bit set in features */
+ CMD_TRNG_COLLECT_ENTROPY = 0x28,
+
+ /* available if CRYPTO bit set in features */
+ CMD_CRYPTO_GET_PUBLIC_KEY = 0x29,
+ CMD_CRYPTO_SIGN_MESSAGE = 0x2A,
+ CMD_CRYPTO_COLLECT_SIGNATURE = 0x2B,
+
+ /* available if BOARD_INFO it set in features */
+ CMD_BOARD_INFO_GET = 0x2C,
+ CMD_BOARD_INFO_BURN = 0x2D,
+
+ /* available only at address 0x2b (led-controller) */
+ /* available only if LED_GAMMA_CORRECTION bit set in features */
+ CMD_SET_GAMMA_CORRECTION = 0x30,
+ CMD_GET_GAMMA_CORRECTION = 0x31,
+
+ /* available only at address 0x2b (led-controller) */
+ /* available only if PER_LED_CORRECTION bit set in features */
+ /* available only if FROM_BIT_16_INVALID bit NOT set in features */
+ CMD_SET_LED_CORRECTIONS = 0x32,
+ CMD_GET_LED_CORRECTIONS = 0x33,
+};
+
+enum omnia_flashing_commands_e {
+ FLASH_CMD_UNLOCK = 0x01,
+ FLASH_CMD_SIZE_AND_CSUM = 0x02,
+ FLASH_CMD_PROGRAM = 0x03,
+ FLASH_CMD_RESET = 0x04,
+};
+
+enum omnia_sts_word_e {
+ STS_MCU_TYPE_MASK = GENMASK(1, 0),
+ STS_MCU_TYPE_STM32 = 0 << 0,
+ STS_MCU_TYPE_GD32 = 1 << 0,
+ STS_MCU_TYPE_MKL = 2 << 0,
+ STS_FEATURES_SUPPORTED = BIT(2),
+ STS_USER_REGULATOR_NOT_SUPPORTED = BIT(3),
+ STS_CARD_DET = BIT(4),
+ STS_MSATA_IND = BIT(5),
+ STS_USB30_OVC = BIT(6),
+ STS_USB31_OVC = BIT(7),
+ STS_USB30_PWRON = BIT(8),
+ STS_USB31_PWRON = BIT(9),
+ STS_ENABLE_4V5 = BIT(10),
+ STS_BUTTON_MODE = BIT(11),
+ STS_BUTTON_PRESSED = BIT(12),
+ STS_BUTTON_COUNTER_MASK = GENMASK(15, 13)
+};
+
+enum omnia_ctl_byte_e {
+ CTL_LIGHT_RST = BIT(0),
+ CTL_HARD_RST = BIT(1),
+ /* BIT(2) is currently reserved */
+ CTL_USB30_PWRON = BIT(3),
+ CTL_USB31_PWRON = BIT(4),
+ CTL_ENABLE_4V5 = BIT(5),
+ CTL_BUTTON_MODE = BIT(6),
+ CTL_BOOTLOADER = BIT(7)
+};
+
+enum omnia_features_e {
+ FEAT_PERIPH_MCU = BIT(0),
+ FEAT_EXT_CMDS = BIT(1),
+ FEAT_WDT_PING = BIT(2),
+ FEAT_LED_STATE_EXT_MASK = GENMASK(4, 3),
+ FEAT_LED_STATE_EXT = 1 << 3,
+ FEAT_LED_STATE_EXT_V32 = 2 << 3,
+ FEAT_LED_GAMMA_CORRECTION = BIT(5),
+ FEAT_NEW_INT_API = BIT(6),
+ FEAT_BOOTLOADER = BIT(7),
+ FEAT_FLASHING = BIT(8),
+ FEAT_NEW_MESSAGE_API = BIT(9),
+ FEAT_BRIGHTNESS_INT = BIT(10),
+ FEAT_POWEROFF_WAKEUP = BIT(11),
+ FEAT_CAN_OLD_MESSAGE_API = BIT(12),
+ FEAT_TRNG = BIT(13),
+ FEAT_CRYPTO = BIT(14),
+ FEAT_BOARD_INFO = BIT(15),
+
+ /*
+ * Orginally the features command replied only 16 bits. If more were
+ * read, either the I2C transaction failed or 0xff bytes were sent.
+ * Therefore to consider bits 16 - 31 valid, one bit (20) was reserved
+ * to be zero.
+ */
+
+ /* Bits 16 - 19 correspond to bits 0 - 3 of status word */
+ FEAT_MCU_TYPE_MASK = GENMASK(17, 16),
+ FEAT_MCU_TYPE_STM32 = FIELD_PREP(FEAT_MCU_TYPE_MASK, 0),
+ FEAT_MCU_TYPE_GD32 = FIELD_PREP(FEAT_MCU_TYPE_MASK, 1),
+ FEAT_MCU_TYPE_MKL = FIELD_PREP(FEAT_MCU_TYPE_MASK, 2),
+ FEAT_FEATURES_SUPPORTED = BIT(18),
+ FEAT_USER_REGULATOR_NOT_SUPPORTED = BIT(19),
+
+ /* must not be set */
+ FEAT_FROM_BIT_16_INVALID = BIT(20),
+
+ FEAT_PER_LED_CORRECTION = BIT(21),
+};
+
+enum omnia_ext_sts_dword_e {
+ EXT_STS_SFP_nDET = BIT(0),
+ EXT_STS_LED_STATES_MASK = GENMASK(31, 12),
+ EXT_STS_WLAN0_MSATA_LED = BIT(12),
+ EXT_STS_WLAN1_LED = BIT(13),
+ EXT_STS_WLAN2_LED = BIT(14),
+ EXT_STS_WPAN0_LED = BIT(15),
+ EXT_STS_WPAN1_LED = BIT(16),
+ EXT_STS_WPAN2_LED = BIT(17),
+ EXT_STS_WAN_LED0 = BIT(18),
+ EXT_STS_WAN_LED1 = BIT(19),
+ EXT_STS_LAN0_LED0 = BIT(20),
+ EXT_STS_LAN0_LED1 = BIT(21),
+ EXT_STS_LAN1_LED0 = BIT(22),
+ EXT_STS_LAN1_LED1 = BIT(23),
+ EXT_STS_LAN2_LED0 = BIT(24),
+ EXT_STS_LAN2_LED1 = BIT(25),
+ EXT_STS_LAN3_LED0 = BIT(26),
+ EXT_STS_LAN3_LED1 = BIT(27),
+ EXT_STS_LAN4_LED0 = BIT(28),
+ EXT_STS_LAN4_LED1 = BIT(29),
+ EXT_STS_LAN5_LED0 = BIT(30),
+ EXT_STS_LAN5_LED1 = BIT(31),
+};
+
+enum omnia_ext_ctl_e {
+ EXT_CTL_nRES_MMC = BIT(0),
+ EXT_CTL_nRES_LAN = BIT(1),
+ EXT_CTL_nRES_PHY = BIT(2),
+ EXT_CTL_nPERST0 = BIT(3),
+ EXT_CTL_nPERST1 = BIT(4),
+ EXT_CTL_nPERST2 = BIT(5),
+ EXT_CTL_PHY_SFP = BIT(6),
+ EXT_CTL_PHY_SFP_AUTO = BIT(7),
+ EXT_CTL_nVHV_CTRL = BIT(8),
+};
+
+enum omnia_int_e {
+ INT_CARD_DET = BIT(0),
+ INT_MSATA_IND = BIT(1),
+ INT_USB30_OVC = BIT(2),
+ INT_USB31_OVC = BIT(3),
+ INT_BUTTON_PRESSED = BIT(4),
+ INT_SFP_nDET = BIT(5),
+ INT_BRIGHTNESS_CHANGED = BIT(6),
+ INT_TRNG = BIT(7),
+ INT_MESSAGE_SIGNED = BIT(8),
+
+ INT_LED_STATES_MASK = GENMASK(31, 12),
+ INT_WLAN0_MSATA_LED = BIT(12),
+ INT_WLAN1_LED = BIT(13),
+ INT_WLAN2_LED = BIT(14),
+ INT_WPAN0_LED = BIT(15),
+ INT_WPAN1_LED = BIT(16),
+ INT_WPAN2_LED = BIT(17),
+ INT_WAN_LED0 = BIT(18),
+ INT_WAN_LED1 = BIT(19),
+ INT_LAN0_LED0 = BIT(20),
+ INT_LAN0_LED1 = BIT(21),
+ INT_LAN1_LED0 = BIT(22),
+ INT_LAN1_LED1 = BIT(23),
+ INT_LAN2_LED0 = BIT(24),
+ INT_LAN2_LED1 = BIT(25),
+ INT_LAN3_LED0 = BIT(26),
+ INT_LAN3_LED1 = BIT(27),
+ INT_LAN4_LED0 = BIT(28),
+ INT_LAN4_LED1 = BIT(29),
+ INT_LAN5_LED0 = BIT(30),
+ INT_LAN5_LED1 = BIT(31),
+};
+
+enum omnia_cmd_poweroff_e {
+ CMD_POWER_OFF_POWERON_BUTTON = BIT(0),
+ CMD_POWER_OFF_MAGIC = 0xdead,
+};
+
+#endif /* __TURRIS_OMNIA_MCU_INTERFACE_H */
--
2.43.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 05/11] platform: cznic: turris-omnia-mcu: Add support for MCU watchdog
2024-03-23 16:43 [PATCH v5 00/11] Turris Omnia MCU driver Marek Behún
2024-03-23 16:43 ` [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU Marek Behún
@ 2024-03-23 16:43 ` Marek Behún
1 sibling, 0 replies; 8+ messages in thread
From: Marek Behún @ 2024-03-23 16:43 UTC (permalink / raw)
To: Arnd Bergmann, Gregory CLEMENT, soc, arm, Andy Shevchenko,
Bartosz Golaszewski, Guenter Roeck, Linus Walleij,
linux-watchdog, Wim Van Sebroeck
Cc: Marek Behún
Add support for the watchdog mechanism provided by the MCU.
Signed-off-by: Marek Behún <kabel@kernel.org>
---
drivers/platform/cznic/Kconfig | 2 +
drivers/platform/cznic/Makefile | 1 +
.../platform/cznic/turris-omnia-mcu-base.c | 4 +
.../cznic/turris-omnia-mcu-watchdog.c | 122 ++++++++++++++++++
drivers/platform/cznic/turris-omnia-mcu.h | 24 ++++
5 files changed, 153 insertions(+)
create mode 100644 drivers/platform/cznic/turris-omnia-mcu-watchdog.c
diff --git a/drivers/platform/cznic/Kconfig b/drivers/platform/cznic/Kconfig
index 0a752aa654fa..e2649cdecc38 100644
--- a/drivers/platform/cznic/Kconfig
+++ b/drivers/platform/cznic/Kconfig
@@ -20,6 +20,7 @@ config TURRIS_OMNIA_MCU
select GPIOLIB
select GPIOLIB_IRQCHIP
select RTC_CLASS
+ select WATCHDOG_CORE
help
Say Y here to add support for the features implemented by the
microcontroller on the CZ.NIC's Turris Omnia SOHO router.
@@ -27,6 +28,7 @@ config TURRIS_OMNIA_MCU
- board poweroff into true low power mode (with voltage regulators
disabled) and the ability to configure wake up from this mode (via
rtcwake)
+ - MCU watchdog
- GPIO pins
- to get front button press events (the front button can be
configured either to generate press events to the CPU or to change
diff --git a/drivers/platform/cznic/Makefile b/drivers/platform/cznic/Makefile
index 6f1470d1f673..a43997a12d74 100644
--- a/drivers/platform/cznic/Makefile
+++ b/drivers/platform/cznic/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o
turris-omnia-mcu-objs := turris-omnia-mcu-base.o
turris-omnia-mcu-objs += turris-omnia-mcu-gpio.o
turris-omnia-mcu-objs += turris-omnia-mcu-sys-off-wakeup.o
+turris-omnia-mcu-objs += turris-omnia-mcu-watchdog.o
diff --git a/drivers/platform/cznic/turris-omnia-mcu-base.c b/drivers/platform/cznic/turris-omnia-mcu-base.c
index 6ab4494335ca..5a45834003cd 100644
--- a/drivers/platform/cznic/turris-omnia-mcu-base.c
+++ b/drivers/platform/cznic/turris-omnia-mcu-base.c
@@ -331,6 +331,10 @@ static int omnia_mcu_probe(struct i2c_client *client)
if (err)
return err;
+ err = omnia_mcu_register_watchdog(mcu);
+ if (err)
+ return err;
+
return omnia_mcu_register_gpiochip(mcu);
}
diff --git a/drivers/platform/cznic/turris-omnia-mcu-watchdog.c b/drivers/platform/cznic/turris-omnia-mcu-watchdog.c
new file mode 100644
index 000000000000..94cdd6eea4c8
--- /dev/null
+++ b/drivers/platform/cznic/turris-omnia-mcu-watchdog.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CZ.NIC's Turris Omnia MCU watchdog driver
+ *
+ * 2024 by Marek Behún <kabel@kernel.org>
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/turris-omnia-mcu-interface.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+#include "turris-omnia-mcu.h"
+
+#define WATCHDOG_TIMEOUT 120
+
+static unsigned int timeout;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int omnia_wdt_start(struct watchdog_device *wdt)
+{
+ struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
+
+ return omnia_cmd_write_u8(mcu->client, CMD_SET_WATCHDOG_STATE, 1);
+}
+
+static int omnia_wdt_stop(struct watchdog_device *wdt)
+{
+ struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
+
+ return omnia_cmd_write_u8(mcu->client, CMD_SET_WATCHDOG_STATE, 0);
+}
+
+static int omnia_wdt_ping(struct watchdog_device *wdt)
+{
+ struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
+
+ return omnia_cmd_write_u8(mcu->client, CMD_SET_WATCHDOG_STATE, 1);
+}
+
+static int omnia_wdt_set_timeout(struct watchdog_device *wdt,
+ unsigned int timeout)
+{
+ struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
+
+ return omnia_cmd_write_u16(mcu->client, CMD_SET_WDT_TIMEOUT,
+ timeout * 10);
+}
+
+static unsigned int omnia_wdt_get_timeleft(struct watchdog_device *wdt)
+{
+ struct omnia_mcu *mcu = watchdog_get_drvdata(wdt);
+ int ret;
+
+ ret = omnia_cmd_read_u16(mcu->client, CMD_GET_WDT_TIMELEFT);
+ if (ret < 0) {
+ dev_err(&mcu->client->dev, "Cannot get watchdog timeleft: %d\n",
+ ret);
+ return 0;
+ }
+
+ return ret / 10;
+}
+
+static const struct watchdog_info omnia_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+ .identity = "Turris Omnia MCU Watchdog",
+};
+
+static const struct watchdog_ops omnia_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = omnia_wdt_start,
+ .stop = omnia_wdt_stop,
+ .ping = omnia_wdt_ping,
+ .set_timeout = omnia_wdt_set_timeout,
+ .get_timeleft = omnia_wdt_get_timeleft,
+};
+
+int omnia_mcu_register_watchdog(struct omnia_mcu *mcu)
+{
+ struct device *dev = &mcu->client->dev;
+ int ret;
+
+ if (!(mcu->features & FEAT_WDT_PING))
+ return 0;
+
+ mcu->wdt.info = &omnia_wdt_info;
+ mcu->wdt.ops = &omnia_wdt_ops;
+ mcu->wdt.parent = dev;
+ mcu->wdt.min_timeout = 1;
+ mcu->wdt.max_timeout = 6553; /* 65535 deciseconds */
+
+ mcu->wdt.timeout = WATCHDOG_TIMEOUT;
+ watchdog_init_timeout(&mcu->wdt, timeout, dev);
+
+ watchdog_set_drvdata(&mcu->wdt, mcu);
+
+ omnia_wdt_set_timeout(&mcu->wdt, mcu->wdt.timeout);
+
+ ret = omnia_cmd_read_u8(mcu->client, CMD_GET_WATCHDOG_STATE);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "Cannot get MCU watchdog state\n");
+
+ if (ret)
+ set_bit(WDOG_HW_RUNNING, &mcu->wdt.status);
+
+ watchdog_set_nowayout(&mcu->wdt, nowayout);
+ watchdog_stop_on_reboot(&mcu->wdt);
+ ret = devm_watchdog_register_device(dev, &mcu->wdt);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Cannot register MCU watchdog\n");
+
+ return 0;
+}
diff --git a/drivers/platform/cznic/turris-omnia-mcu.h b/drivers/platform/cznic/turris-omnia-mcu.h
index af9845d1c6d2..3e2c96079e64 100644
--- a/drivers/platform/cznic/turris-omnia-mcu.h
+++ b/drivers/platform/cznic/turris-omnia-mcu.h
@@ -15,6 +15,7 @@
#include <linux/mutex.h>
#include <linux/rtc.h>
#include <linux/types.h>
+#include <linux/watchdog.h>
#include <linux/workqueue.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
@@ -42,6 +43,9 @@ struct omnia_mcu {
struct rtc_device *rtcdev;
u32 rtc_alarm;
bool front_button_poweron;
+
+ /* MCU watchdog */
+ struct watchdog_device wdt;
};
static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
@@ -54,6 +58,25 @@ static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
return ret < 0 ? ret : 0;
}
+static inline int omnia_cmd_write_u8(const struct i2c_client *client, u8 cmd,
+ u8 val)
+{
+ u8 buf[2] = { cmd, val };
+
+ return omnia_cmd_write(client, buf, sizeof(buf));
+}
+
+static inline int omnia_cmd_write_u16(const struct i2c_client *client, u8 cmd,
+ u16 val)
+{
+ u8 buf[3];
+
+ buf[0] = cmd;
+ put_unaligned_le16(val, &buf[1]);
+
+ return omnia_cmd_write(client, buf, sizeof(buf));
+}
+
static inline int omnia_cmd_write_u32(const struct i2c_client *client, u8 cmd,
u32 val)
{
@@ -148,5 +171,6 @@ extern const struct attribute_group omnia_mcu_poweroff_group;
int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu);
int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu);
+int omnia_mcu_register_watchdog(struct omnia_mcu *mcu);
#endif /* __TURRIS_OMNIA_MCU_H */
--
2.43.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU
2024-03-23 16:43 ` [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU Marek Behún
@ 2024-03-24 11:01 ` Andy Shevchenko
2024-03-24 15:04 ` Marek Behún
0 siblings, 1 reply; 8+ messages in thread
From: Andy Shevchenko @ 2024-03-24 11:01 UTC (permalink / raw)
To: Marek Behún
Cc: Arnd Bergmann, Gregory CLEMENT, soc, arm, Linus Walleij,
Bartosz Golaszewski, Andy Shevchenko, linux-gpio,
Alessandro Zummo, Alexandre Belloni, linux-rtc, Wim Van Sebroeck,
Guenter Roeck, linux-watchdog
Sat, Mar 23, 2024 at 05:43:50PM +0100, Marek Behún kirjoitti:
> Add the basic skeleton for a new platform driver for the microcontroller
> found on the Turris Omnia board.
...
> +++ b/drivers/platform/cznic/Makefile
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +
> +obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o
> +turris-omnia-mcu-objs := turris-omnia-mcu-base.o
'objs' is for user space. You need to use 'y'. Same applies to the entire
series.
...
+ array_size.h
+ bits.h
> +#include <linux/device.h>
> +#include <linux/hex.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/turris-omnia-mcu-interface.h>
> +#include <linux/types.h>
+ string.h
> +#include <linux/sysfs.h>
...
> + err = omnia_cmd_read(mcu->client, bootloader ? CMD_GET_FW_VERSION_BOOT :
> + CMD_GET_FW_VERSION_APP,
> + reply, sizeof(reply));
Wouldn't be better to have a logical split?
err = omnia_cmd_read(mcu->client,
bootloader ? CMD_GET_FW_VERSION_BOOT : CMD_GET_FW_VERSION_APP,
reply, sizeof(reply));
?
...
> + struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
What's wrong with dev_get_drvdata()?
...
> +static ssize_t fw_features_show(struct device *dev, struct device_attribute *a,
> + char *buf)
One line?
...
> + struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
Use direct call (see above). Same applies to all such constructions in your
code.
...
> +static const struct attribute_group omnia_mcu_base_group = {
> + .attrs = omnia_mcu_base_attrs,
> + .is_visible = omnia_mcu_base_attrs_visible,
> +};
> +
> +static const struct attribute_group *omnia_mcu_groups[] = {
> + &omnia_mcu_base_group,
> + NULL
> +};
__ATTRIBUTE_GROUPS()
...
> +static struct i2c_driver omnia_mcu_driver = {
> + .probe = omnia_mcu_probe,
> + .driver = {
> + .name = "turris-omnia-mcu",
> + .of_match_table = of_omnia_mcu_match,
> + .dev_groups = omnia_mcu_groups,
> + },
> +};
> +
Redundant blank line.
> +module_i2c_driver(omnia_mcu_driver);
...
> +#ifndef __TURRIS_OMNIA_MCU_H
> +#define __TURRIS_OMNIA_MCU_H
+ array_size.h
> +#include <linux/i2c.h>
> +#include <linux/if_ether.h>
> +#include <linux/types.h>
> +#include <asm/byteorder.h>
...
> +static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
> + void *reply, unsigned int len)
> +{
Why is this in the header?
> + struct i2c_msg msgs[2];
> + int ret;
> +
> + msgs[0].addr = client->addr;
> + msgs[0].flags = 0;
> + msgs[0].len = 1;
> + msgs[0].buf = &cmd;
> + msgs[1].addr = client->addr;
> + msgs[1].flags = I2C_M_RD;
> + msgs[1].len = len;
> + msgs[1].buf = reply;
> +
> + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
> + if (ret < 0)
> + return ret;
> + if (ret != ARRAY_SIZE(msgs))
> + return -EIO;
> +
> + return 0;
> +}
...
> +#ifndef __TURRIS_OMNIA_MCU_INTERFACE_H
> +#define __TURRIS_OMNIA_MCU_INTERFACE_H
> +
> +#include <linux/bits.h>
+ bitfield.h
> +#endif /* __TURRIS_OMNIA_MCU_INTERFACE_H */
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU
2024-03-24 11:01 ` Andy Shevchenko
@ 2024-03-24 15:04 ` Marek Behún
2024-03-24 15:30 ` Andy Shevchenko
0 siblings, 1 reply; 8+ messages in thread
From: Marek Behún @ 2024-03-24 15:04 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Arnd Bergmann, Gregory CLEMENT, soc, arm, Linus Walleij,
Bartosz Golaszewski, Andy Shevchenko, linux-gpio,
Alessandro Zummo, Alexandre Belloni, linux-rtc, Wim Van Sebroeck,
Guenter Roeck, linux-watchdog
Hi Andy,
thank you very much for the review. I have some notes and some
questions, see below.
On Sun, 24 Mar 2024 13:01:55 +0200
Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> Sat, Mar 23, 2024 at 05:43:50PM +0100, Marek Behún kirjoitti:
> > Add the basic skeleton for a new platform driver for the microcontroller
> > found on the Turris Omnia board.
>
> ...
>
> > +++ b/drivers/platform/cznic/Makefile
> > @@ -0,0 +1,4 @@
> > +# SPDX-License-Identifier: GPL-2.0-only
> > +
> > +obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o
> > +turris-omnia-mcu-objs := turris-omnia-mcu-base.o
>
> 'objs' is for user space. You need to use 'y'. Same applies to the entire
> series.
Fixed for v6.
>
> + array_size.h
> + bits.h
Fixed for v6. Is there some tool for this?
> + string.h
Fixed for v6.
>
> > +#include <linux/sysfs.h>
>
> ...
>
> > + err = omnia_cmd_read(mcu->client, bootloader ? CMD_GET_FW_VERSION_BOOT :
> > + CMD_GET_FW_VERSION_APP,
> > + reply, sizeof(reply));
>
> Wouldn't be better to have a logical split?
>
> err = omnia_cmd_read(mcu->client,
> bootloader ? CMD_GET_FW_VERSION_BOOT : CMD_GET_FW_VERSION_APP,
> reply, sizeof(reply));
Changed for v6 to
> err = omnia_cmd_read(mcu->client,
> bootloader ? CMD_GET_FW_VERSION_BOOT
> : CMD_GET_FW_VERSION_APP,
> reply, sizeof(reply));
There are still some people wanting only 80 columns, and the whole
driver is written that way.
>
> ?
>
> ...
>
> > + struct omnia_mcu *mcu = i2c_get_clientdata(to_i2c_client(dev));
>
> What's wrong with dev_get_drvdata()?
Fixed for v6.
> ...
>
> > +static ssize_t fw_features_show(struct device *dev, struct device_attribute *a,
> > + char *buf)
>
> One line?
80 columns...
...
> > +static const struct attribute_group omnia_mcu_base_group = {
> > + .attrs = omnia_mcu_base_attrs,
> > + .is_visible = omnia_mcu_base_attrs_visible,
> > +};
> > +
> > +static const struct attribute_group *omnia_mcu_groups[] = {
> > + &omnia_mcu_base_group,
> > + NULL
> > +};
>
> __ATTRIBUTE_GROUPS()
The next patches add more groups into this array, after the whole
series it looks like this:
static const struct attribute_group *omnia_mcu_groups[] = {
&omnia_mcu_base_group,
&omnia_mcu_gpio_group,
&omnia_mcu_poweroff_group,
NULL
};
There is no macro for that. Should I still use __ATTRIBUTE_GROUPS() in
the first patch and than change it in the next one?
>
> ...
>
> > +static struct i2c_driver omnia_mcu_driver = {
> > + .probe = omnia_mcu_probe,
> > + .driver = {
> > + .name = "turris-omnia-mcu",
> > + .of_match_table = of_omnia_mcu_match,
> > + .dev_groups = omnia_mcu_groups,
> > + },
> > +};
>
> > +
>
> Redundant blank line.
>
Fixed for v6.
> > +module_i2c_driver(omnia_mcu_driver);
>
> ...
>
> > +#ifndef __TURRIS_OMNIA_MCU_H
> > +#define __TURRIS_OMNIA_MCU_H
>
> + array_size.h
Fixed for v6.
>
> > +#include <linux/i2c.h>
> > +#include <linux/if_ether.h>
> > +#include <linux/types.h>
> > +#include <asm/byteorder.h>
>
> ...
>
> > +static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
> > + void *reply, unsigned int len)
> > +{
>
> Why is this in the header?
I considered it a helper function that should be defined in the header
file, like the rest of the cmd helpers in this file. If you disagree, I
will put it into the -base.c file.
>
> > + struct i2c_msg msgs[2];
> > + int ret;
> > +
> > + msgs[0].addr = client->addr;
> > + msgs[0].flags = 0;
> > + msgs[0].len = 1;
> > + msgs[0].buf = &cmd;
> > + msgs[1].addr = client->addr;
> > + msgs[1].flags = I2C_M_RD;
> > + msgs[1].len = len;
> > + msgs[1].buf = reply;
> > +
> > + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
> > + if (ret < 0)
> > + return ret;
> > + if (ret != ARRAY_SIZE(msgs))
> > + return -EIO;
> > +
> > + return 0;
> > +}
>
> ...
>
> > +#ifndef __TURRIS_OMNIA_MCU_INTERFACE_H
> > +#define __TURRIS_OMNIA_MCU_INTERFACE_H
> > +
> > +#include <linux/bits.h>
>
> + bitfield.h
Fixed for v6.
>
> > +#endif /* __TURRIS_OMNIA_MCU_INTERFACE_H */
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU
2024-03-24 15:04 ` Marek Behún
@ 2024-03-24 15:30 ` Andy Shevchenko
2024-03-25 10:39 ` Marek Behún
2024-04-02 16:41 ` Marek Behún
0 siblings, 2 replies; 8+ messages in thread
From: Andy Shevchenko @ 2024-03-24 15:30 UTC (permalink / raw)
To: Marek Behún
Cc: Arnd Bergmann, Gregory CLEMENT, soc, arm, Linus Walleij,
Bartosz Golaszewski, Andy Shevchenko, linux-gpio,
Alessandro Zummo, Alexandre Belloni, linux-rtc, Wim Van Sebroeck,
Guenter Roeck, linux-watchdog
On Sun, Mar 24, 2024 at 5:04 PM Marek Behún <kabel@kernel.org> wrote:
>
> Hi Andy,
>
> thank you very much for the review. I have some notes and some
> questions, see below.
Btw, I'll look into other patches next week.
> On Sun, 24 Mar 2024 13:01:55 +0200
> Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> > Sat, Mar 23, 2024 at 05:43:50PM +0100, Marek Behún kirjoitti:
...
> > > + err = omnia_cmd_read(mcu->client, bootloader ? CMD_GET_FW_VERSION_BOOT :
> > > + CMD_GET_FW_VERSION_APP,
> > > + reply, sizeof(reply));
> >
> > Wouldn't be better to have a logical split?
> >
> > err = omnia_cmd_read(mcu->client,
> > bootloader ? CMD_GET_FW_VERSION_BOOT : CMD_GET_FW_VERSION_APP,
> > reply, sizeof(reply));
>
> Changed for v6 to
>
> > err = omnia_cmd_read(mcu->client,
> > bootloader ? CMD_GET_FW_VERSION_BOOT
> > : CMD_GET_FW_VERSION_APP,
> > reply, sizeof(reply));
>
> There are still some people wanting only 80 columns, and the whole
> driver is written that way.
Hmm... Is it still a hard limit for drivers/platform/cznic for the _new_ code?
> > ?
...
> > > +static ssize_t fw_features_show(struct device *dev, struct device_attribute *a,
> > > + char *buf)
> >
> > One line?
>
> 80 columns...
Ditto.
...
> > > +static const struct attribute_group *omnia_mcu_groups[] = {
> > > + &omnia_mcu_base_group,
> > > + NULL
> > > +};
> >
> > __ATTRIBUTE_GROUPS()
>
> The next patches add more groups into this array, after the whole
> series it looks like this:
>
> static const struct attribute_group *omnia_mcu_groups[] = {
> &omnia_mcu_base_group,
> &omnia_mcu_gpio_group,
> &omnia_mcu_poweroff_group,
> NULL
> };
>
> There is no macro for that.
Good point.
> Should I still use __ATTRIBUTE_GROUPS() in
> the first patch and than change it in the next one?
...
> > > +static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
> > > + void *reply, unsigned int len)
> > > +{
> >
> > Why is this in the header?
>
> I considered it a helper function that should be defined in the header
> file, like the rest of the cmd helpers in this file. If you disagree, I
> will put it into the -base.c file.
I don't see the technical justification to hold it in the *.h rather
than *.c. To me this one is big enough in C and likely in assembly to
be copied to each user. Besides that aspect, it slows down the build a
lot (mostly due to i2c.h inclusion which otherwise is not needed).
> > > + struct i2c_msg msgs[2];
> > > + int ret;
> > > +
> > > + msgs[0].addr = client->addr;
> > > + msgs[0].flags = 0;
> > > + msgs[0].len = 1;
> > > + msgs[0].buf = &cmd;
> > > + msgs[1].addr = client->addr;
> > > + msgs[1].flags = I2C_M_RD;
> > > + msgs[1].len = len;
> > > + msgs[1].buf = reply;
> > > +
> > > + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
> > > + if (ret < 0)
> > > + return ret;
> > > + if (ret != ARRAY_SIZE(msgs))
> > > + return -EIO;
> > > +
> > > + return 0;
> > > +}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU
2024-03-24 15:30 ` Andy Shevchenko
@ 2024-03-25 10:39 ` Marek Behún
2024-04-02 16:41 ` Marek Behún
1 sibling, 0 replies; 8+ messages in thread
From: Marek Behún @ 2024-03-25 10:39 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Arnd Bergmann, Gregory CLEMENT, soc, arm, Linus Walleij,
Bartosz Golaszewski, Andy Shevchenko, linux-gpio,
Alessandro Zummo, Alexandre Belloni, linux-rtc, Wim Van Sebroeck,
Guenter Roeck, linux-watchdog
On Sun, 24 Mar 2024 17:30:39 +0200
Andy Shevchenko <andy.shevchenko@gmail.com> wrote:
> On Sun, Mar 24, 2024 at 5:04 PM Marek Behún <kabel@kernel.org> wrote:
> >
> > Hi Andy,
> >
> > thank you very much for the review. I have some notes and some
> > questions, see below.
>
> Btw, I'll look into other patches next week.
Thx.
...
> >
> > There are still some people wanting only 80 columns, and the whole
> > driver is written that way.
>
> Hmm... Is it still a hard limit for drivers/platform/cznic for the _new_ code?
I don't think so, but I personally would also prefer leaving this at 80
columns. Is this a problem?
> > I considered it a helper function that should be defined in the header
> > file, like the rest of the cmd helpers in this file. If you disagree, I
> > will put it into the -base.c file.
>
> I don't see the technical justification to hold it in the *.h rather
> than *.c. To me this one is big enough in C and likely in assembly to
> be copied to each user. Besides that aspect, it slows down the build a
> lot (mostly due to i2c.h inclusion which otherwise is not needed).
OK, I moved it into -base.c.
Marek
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU
2024-03-24 15:30 ` Andy Shevchenko
2024-03-25 10:39 ` Marek Behún
@ 2024-04-02 16:41 ` Marek Behún
1 sibling, 0 replies; 8+ messages in thread
From: Marek Behún @ 2024-04-02 16:41 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Marek Behún, Arnd Bergmann, Gregory CLEMENT, soc, arm,
Linus Walleij, Bartosz Golaszewski, Andy Shevchenko, linux-gpio,
Alessandro Zummo, Alexandre Belloni, linux-rtc, Wim Van Sebroeck,
Guenter Roeck, linux-watchdog
On Sun, Mar 24, 2024 at 05:30:39PM +0200, Andy Shevchenko wrote:
> On Sun, Mar 24, 2024 at 5:04 PM Marek Behún <kabel@kernel.org> wrote:
> >
> > Hi Andy,
> >
> > thank you very much for the review. I have some notes and some
> > questions, see below.
>
> Btw, I'll look into other patches next week.
Hello Andy,
did you have a chance to look at the other patches?
Marek
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2024-04-02 16:51 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-23 16:43 [PATCH v5 00/11] Turris Omnia MCU driver Marek Behún
2024-03-23 16:43 ` [PATCH v5 02/11] platform: cznic: Add preliminary support for Turris Omnia MCU Marek Behún
2024-03-24 11:01 ` Andy Shevchenko
2024-03-24 15:04 ` Marek Behún
2024-03-24 15:30 ` Andy Shevchenko
2024-03-25 10:39 ` Marek Behún
2024-04-02 16:41 ` Marek Behún
2024-03-23 16:43 ` [PATCH v5 05/11] platform: cznic: turris-omnia-mcu: Add support for MCU watchdog Marek Behún
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).