Skip to contentSkip to conversation

Turris Omnia MCU driver

PATCH Superseded Marek Behún 4 participants 30 messages Apr 30, 2024 – May 7, 2024

Subsystems (7)

v8 of 13 Superseded Latest is v13 →

lore
Share & tools
lore

Marek Behún

author maintainer
#0 lore raw

v8 cover Turris Omnia MCU driver

Hello Andy, Hans, Ilpo, Arnd, Gregory, and others,

this is v8 of the series adding Turris Omnia MCU driver.

This series depends on the immutable branch between LEDs and locking, introducing devm_mutex_init(), see the PR
https://lore.kernel.org/linux-leds/[email protected]/

See also cover letters for v1, v2, v3, v4, v5, v6 and v7:
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/

Changes since v7:
- fixed wrong $id path in DT binding (patch 1)
- removed resource managed IRQ mapping disposal, which is not needed, as pointed out by Andy (patches 6, 7)
- added some more #includes (for linux/device.h, linux/interrupt.h, linux/hw_random.h) (patches 3, 6, 7)
- dropped the Fixes tags from the DT changes (patches 8, 9), with an explanation of this added into the commit message of patch 8, as suggested by Andrew

Marek Behún (9):
dt-bindings: firmware: 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
platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG
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 ++
 .../firmware/cznic,turris-omnia-mcu.yaml      |   86 ++
 MAINTAINERS                                   |    5 +
 .../dts/marvell/armada-385-turris-omnia.dts   |   35 +-
 drivers/platform/Kconfig                      |    2 +
 drivers/platform/Makefile                     |    1 +
 drivers/platform/cznic/Kconfig                |   51 +
 drivers/platform/cznic/Makefile               |    9 +
 .../platform/cznic/turris-omnia-mcu-base.c    |  439 +++++++
 .../platform/cznic/turris-omnia-mcu-debugfs.c |  207 ++++
 .../platform/cznic/turris-omnia-mcu-gpio.c    | 1048 +++++++++++++++++
 .../cznic/turris-omnia-mcu-sys-off-wakeup.c   |  258 ++++
 .../platform/cznic/turris-omnia-mcu-trng.c    |  101 ++
 .../cznic/turris-omnia-mcu-watchdog.c         |  123 ++
 drivers/platform/cznic/turris-omnia-mcu.h     |  188 +++
 include/linux/turris-omnia-mcu-interface.h    |  249 ++++
 17 files changed, 2940 insertions(+), 1 deletion(-)
 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/firmware/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
Signature · 1 line
2.43.2
author maintainer
#1 lore raw

PATCH v8 1/9 dt-bindings: firmware: add cznic,turris-omnia-mcu binding

Add binding for cznic,turris-omnia-mcu, the device-tree node representing the system-controller features provided by the MCU on the Turris Omnia router.

---
 .../firmware/cznic,turris-omnia-mcu.yaml      | 86 +++++++++++++++++++
 MAINTAINERS                                   |  1 +
 2 files changed, 87 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/firmware/cznic,turris-omnia-mcu.yaml
Documentation/devicetree/bindings/firmware/cznic,turris-omnia-mcu.yaml new file +86 -0
new file mode 100644
index 000000000000..af9249695ef5
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/firmware/cznic,turris-omnia-mcu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: CZ.NIC's Turris Omnia MCU
+
+maintainers:
+  - Marek Behún <[email protected]>
+
+description:
+  The MCU on Turris Omnia acts as a system controller providing additional
+  GPIOs, interrupts, watchdog, system power off and wakeup configuration.
+
+properties:
+  compatible:
+    const: cznic,turris-omnia-mcu
+
+  reg:
+    description: MCU I2C slave address
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 2
+    description: |
+      The first cell specifies the interrupt number (0 to 63), the second cell
+      specifies interrupt type (which can be one of IRQ_TYPE_EDGE_RISING,
+      IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_BOTH).
+      The interrupt numbers correspond sequentially to GPIO numbers, taking the
+      GPIO banks into account:
+        IRQ number   GPIO bank   GPIO pin within bank
+           0 - 15      0           0 - 15
+          16 - 47      1           0 - 31
+          48 - 63      2           0 - 15
+      There are several exceptions:
+        IRQ number   meaning
+          11           LED panel brightness changed by button press
+          13           TRNG entropy ready
+          14           ECDSA message signature computation done
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+    description:
+      The first cell is bank number (0, 1 or 2), the second cell is pin number
+      within the bank (0 to 15 for banks 0 and 2, 0 to 31 for bank 1), and the
+      third cell specifies consumer flags.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - gpio-controller
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        system-controller@2a {
+            compatible = "cznic,turris-omnia-mcu";
+            reg = <0x2a>;
+
+            interrupt-parent = <&gpio1>;
+            interrupts = <11 IRQ_TYPE_NONE>;
+
+            gpio-controller;
+            #gpio-cells = <3>;
+
+            interrupt-controller;
+            #interrupt-cells = <2>;
+        };
+    };
MAINTAINERS +1 -0
index ab89edc6974d..359ed2cadfc4 100644
@@ -2143,6 +2143,7 @@ F:	Documentation/ABI/testing/sysfs-bus-moxtet-devices
 F:	Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm
 F:	Documentation/devicetree/bindings/bus/moxtet.txt
 F:	Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt
+F:	Documentation/devicetree/bindings/firmware/cznic,turris-omnia-mcu.yaml
 F:	Documentation/devicetree/bindings/gpio/gpio-moxtet.txt
 F:	Documentation/devicetree/bindings/leds/cznic,turris-omnia-leds.yaml
 F:	Documentation/devicetree/bindings/watchdog/armada-37xx-wdt.txt
Signature · 1 line
2.43.2
author maintainer
#2 lore raw

PATCH v8 2/9 platform: cznic: Add preliminary support for Turris Omnia MCU

In reply to Marek Behún

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

---
 .../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    | 376 ++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |  50 +++
 include/linux/turris-omnia-mcu-interface.h    | 249 ++++++++++++
 9 files changed, 792 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
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu new file +81 -0
new file mode 100644
index 000000000000..ff5e7cb00206
@@ -0,0 +1,81 @@
+What:		/sys/bus/i2c/devices/<mcu_device>/board_revision
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+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 <[email protected]>
+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 <[email protected]>
+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 <[email protected]>
+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 <[email protected]>
+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 <[email protected]>
+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 <[email protected]>
+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 <[email protected]>
+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.
MAINTAINERS +3 -0
index 359ed2cadfc4..2aa178a9d53e 100644
@@ -2139,6 +2139,7 @@ M:	Marek Behún <[email protected]>
 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/bus/moxtet.txt
@@ -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 <[email protected]>
drivers/platform/Kconfig +2 -0
index 868b20361769..fef907a94001 100644
@@ -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"
drivers/platform/Makefile +1 -0
index 41640172975a..8bf189264374 100644
@@ -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/
drivers/platform/cznic/Kconfig new file +26 -0
new file mode 100644
index 000000000000..f8560ff9c1af
@@ -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
drivers/platform/cznic/Makefile new file +4 -0
new file mode 100644
index 000000000000..31adca73bb94
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
+turris-omnia-mcu-y		:= turris-omnia-mcu-base.o
drivers/platform/cznic/turris-omnia-mcu-base.c new file +376 -0

376 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h new file +50 -0

50 lines not on this page · raw message

include/linux/turris-omnia-mcu-interface.h new file +249 -0

249 lines not on this page · raw message

Signature · 1 line
2.43.2
#3 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 3 lines · Marek Behún

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

...

Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu line 75

Quoted 5 lines
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu new file +5 -0
+What:          /sys/bus/i2c/devices/<mcu_device>/serial_number
+Date:          July 2024
+KernelVersion: 6.10
+Contact:       Marek Behún <[email protected]>
+Description:   (RO) Contains the 64 bit long board serial number in hexadecimal

64 bit long --> 64-bit

Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu line 81

Quoted 6 lines
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu new file +6 -0
+               format.
+
+               Only available if board information is burned in the MCU (older
+               revisions have board information burned in the ATSHA204-A chip).
+
+               Format: %016X.

It's strange to use capitalized hexadecimal here and not in other files, but maybe it's something special about "serial number"? Dunno.

...

drivers/platform/cznic/Kconfig line 9

Quoted 4 lines
drivers/platform/cznic/Kconfig new file +3 -0
+menuconfig CZNIC_PLATFORMS
+       bool "Platform support for CZ.NIC's Turris hardware"
 
+       depends on MACH_ARMADA_38X || COMPILE_TEST

This...

drivers/platform/cznic/Kconfig line 18

Quoted 10 lines
drivers/platform/cznic/Kconfig new file +9 -0
+       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

...or this dependency is redundant. I think one would expect that these platforms will not be always based on the same platform, hence I would drop the former and leave the latter. But you should know better than me.

Quoted 6 lines
drivers/platform/cznic/Kconfig new file +6 -0
+       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.

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 50

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader,
+                                 u8 version[static OMNIA_FW_VERSION_HEX_LEN])

Interesting format of the last parameter. Does it make any difference to the compiler if you use u8 *version?

drivers/platform/cznic/turris-omnia-mcu-base.c line 63

Quoted 13 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +12 -0
+{
+       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);

Hmm... I would rather use returned value

char *p;

p = bin2hex(...);
*p = '\0';

return 0;

Quoted 2 lines
(quoted diff) +2 -0
+       return 0;
+}

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 173

Quoted 7 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +6 -0
+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 = dev_get_drvdata(dev);
 
+       umode_t mode = a->mode;

Do you need this?

drivers/platform/cznic/turris-omnia-mcu-base.c line 179

Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +5 -0
+       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 0; ?

Quoted 1 line

+ return mode;

return a->mode; ?

Quoted 1 line

+}

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 204

Quoted 11 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +11 -0
+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);

One line?

Quoted 5 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +5 -0
+               return;
+       }
+
+       dev_info(dev, "MCU %s firmware version hash: %s\n", type, version);
+}

...

Quoted 1 line

+static const char *omnia_status_to_mcu_type(uint16_t status)

Why out of a sudden uint16_t instead of u16?

Quoted 12 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +12 -0
+{
+       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";
+       }
+}

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 235

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+       static const struct {
+               uint16_t mask;

Ditto.

Quoted 9 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +9 -0
+               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" },
+       };

...

Quoted 1 line

+ omnia_info_missing_feature(dev, "feature reading");

Tautology. Read the final message. I believe you wanted to pass just "reading" here.

...

Quoted 1 line

+ memcpy(mcu->board_first_mac, &reply[9], ETH_ALEN);

There is an API ether_copy_addr() or so, don't remember by heart. You also need an include for ETH_ALEN definition.

...

Quoted 1 line

+#include <linux/i2c.h>

No users of this, you may replace with

struct i2c_client;

Am I right?

...

Quoted 1 line

+ CMD_GET_FW_VERSION_BOOT = 0x0E, /* 20B git hash number */

Git

...

Quoted 1 line

+ /* available only at address 0x2b (led-controller) */

LED-controller

...

include/linux/turris-omnia-mcu-interface.h line 124

Quoted 9 lines
include/linux/turris-omnia-mcu-interface.h new file +9 -0
+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)

Keep trailing comma as it might be extended (theoretically). And you do the similar in other enums anyway.

Quoted 1 line

+};

--
With Best Regards,
Andy Shevchenko

author maintainer
#4 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 7 lines · On Tue, 30 Apr 2024 15:53:51 +0300 Andy Shevchenko <[email protected]>…
Quoted 3 lines · Marek Behún

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

...

Quoted 7 lines

Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu line 75

Quoted 5 lines
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu new file +5 -0
+What:          /sys/bus/i2c/devices/<mcu_device>/serial_number
+Date:          July 2024
+KernelVersion: 6.10
+Contact:       Marek Behún <[email protected]>
+Description:   (RO) Contains the 64 bit long board serial number in hexadecimal  

64 bit long --> 64-bit

ok

Quoted 10 lines

Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu line 81

Quoted 7 lines
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu new file +6 -0
+               format.
+
+               Only available if board information is burned in the MCU (older
+               revisions have board information burned in the ATSHA204-A chip).
+
+               Format: %016X.  

It's strange to use capitalized hexadecimal here and not in other files, but maybe it's something special about "serial number"? Dunno.

Yes, the serial number is printed with captial hex letters.

Quoted 16 lines

drivers/platform/cznic/Kconfig line 9

Quoted 4 lines
drivers/platform/cznic/Kconfig new file +3 -0
+menuconfig CZNIC_PLATFORMS
+       bool "Platform support for CZ.NIC's Turris hardware"  
 
+       depends on MACH_ARMADA_38X || COMPILE_TEST  

This...

Quoted 8 lines
drivers/platform/cznic/Kconfig new file +8 -0
+       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"  
Quoted 6 lines
Quoted 1 line

+ depends on MACH_ARMADA_38X || COMPILE_TEST

...or this dependency is redundant. I think one would expect that these platforms will not be always based on the same platform, hence I would drop the former and leave the latter. But you should know better than me.

ok

Quoted 8 lines

drivers/platform/cznic/Kconfig line 24

Quoted 7 lines
drivers/platform/cznic/Kconfig new file +6 -0
+       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.  
Quoted 7 lines

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 50

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader,
+                                 u8 version[static OMNIA_FW_VERSION_HEX_LEN])  

Interesting format of the last parameter. Does it make any difference to the compiler if you use u8 *version?

The compiler will warn if an array with not enough space is passed as argument.

Quoted 15 lines
Quoted 4 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +3 -0
+{
+       u8 reply[OMNIA_FW_VERSION_LEN];
+       int err;

drivers/platform/cznic/turris-omnia-mcu-base.c line 63

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +9 -0
+
+       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);  
Quoted 8 lines

Hmm... I would rather use returned value

char *p;

p = bin2hex(...);
*p = '\0';

return 0;

OK. I guess

  *bin2hex(version, reply, OMNIA_FW_VERSION_LEN) = '\0';

would be too crazy, right?

Quoted 21 lines
Quoted 3 lines
(quoted diff) +2 -0
+       return 0;
+}  

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 173

Quoted 7 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +6 -0
+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 = dev_get_drvdata(dev);  
 
+       umode_t mode = a->mode;  

Do you need this?

Quoted 4 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +4 -0
+       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))  
Quoted 7 lines
Quoted 1 line

+ mode = 0;

return 0; ?

Quoted 1 line

+ return mode;

return a->mode; ?

ok

Quoted 5 lines
Quoted 2 lines

+}

...

Quoted 13 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 204

Quoted 11 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +11 -0
+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);  

One line?

I'd like to keep this driver to 80 columns.

Quoted 9 lines
Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +5 -0
+               return;
+       }
+
+       dev_info(dev, "MCU %s firmware version hash: %s\n", type, version);
+}  

...

Quoted 3 lines
Quoted 1 line

+static const char *omnia_status_to_mcu_type(uint16_t status)

Why out of a sudden uint16_t instead of u16?

This was a mistake, thanks.

Quoted 30 lines
Quoted 12 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +12 -0
+{
+       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";
+       }
+}  

...

drivers/platform/cznic/turris-omnia-mcu-base.c line 235

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+       static const struct {
+               uint16_t mask;  

Ditto.

drivers/platform/cznic/turris-omnia-mcu-base.c line 244

Quoted 9 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +9 -0
+               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" },
+       };  
Quoted 6 lines

...

Quoted 1 line

+ omnia_info_missing_feature(dev, "feature reading");

Tautology. Read the final message. I believe you wanted to pass just "reading" here.

No, I actually wanted it to print
Your board's MCU firmware does not support the feature reading feature.
as in the feature "feature reading" is not supported.
I guess I could change it to
Your board's MCU firmware does not support the feature reading.
but that would complicate the code: either I would need to add " feature" suffix to all the features[].name, or duplicate the info string from the omnia_info_missing_feature() function.

Quoted 6 lines

...

Quoted 1 line

+ memcpy(mcu->board_first_mac, &reply[9], ETH_ALEN);

There is an API ether_copy_addr() or so, don't remember by heart. You also need an include for ETH_ALEN definition.

Doc for ether_addr_copy says:
Please note: dst & src must both be aligned to u16.
since the code does:
u16 *a = (u16 *)dst;
const u16 *b = (const u16 *)src;

  a[0] = b[0];
  a[1] = b[1];
  a[2] = b[2]

Since I am copying from &reply[9], which is not u16-aligned, this won't work.

Quoted 9 lines

...

Quoted 1 line

+#include <linux/i2c.h>

No users of this, you may replace with

struct i2c_client;

Am I right?

OK.

Quoted 7 lines

...

Quoted 2 lines

+ CMD_GET_FW_VERSION_BOOT = 0x0E, /* 20B git hash
number */

Git

OK.

Quoted 5 lines

...

Quoted 1 line

+ /* available only at address 0x2b (led-controller) */

LED-controller

OK

Quoted 13 lines

...

include/linux/turris-omnia-mcu-interface.h line 124

Quoted 9 lines
include/linux/turris-omnia-mcu-interface.h new file +9 -0
+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)  
Quoted 2 lines

Keep trailing comma as it might be extended (theoretically). And you do the similar in other enums anyway.

ctl_byt is 8-bit, so this enum really can't be extended. In fact I need to drop the last comma from omnia_ext_sts_dword_e and omnia_int_e.

Thanks, Andy.

#5 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 21 lines · Marek Behún
Quoted 21 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 63

Quoted 13 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +12 -0
+{
+       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);  

Hmm... I would rather use returned value

char *p;

p = bin2hex(...);
*p = '\0';

Quoted 7 lines
Quoted 1 line

return 0;

OK. I guess

  *bin2hex(version, reply, OMNIA_FW_VERSION_LEN) = '\0';

would be too crazy, right?

Indeed. Please don't do that. 0_0

regards,
dan carpenter

#6 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

In reply to Marek Behún
Quoted 3 lines · Marek Behún
Quoted 1 line · On Tue, 30 Apr 2024 15:53:51 +0300 Andy Shevchenko <[email protected]>…

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 8 lines
Quoted 5 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 50

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader,
+                                 u8 version[static OMNIA_FW_VERSION_HEX_LEN])

Interesting format of the last parameter. Does it make any difference to the compiler if you use u8 *version?

The compiler will warn if an array with not enough space is passed as argument.

Really?

Quoted 21 lines
Quoted 21 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 63

Quoted 13 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +12 -0
+{
+       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);  

Hmm... I would rather use returned value

char *p;

p = bin2hex(...);
*p = '\0';

Quoted 7 lines
Quoted 1 line

return 0;

OK. I guess

  *bin2hex(version, reply, OMNIA_FW_VERSION_LEN) = '\0';

would be too crazy, right?

Yes, it's not a Python :-)

Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
(quoted diff) +2 -0
+       return 0;
+}  

...

Quoted 6 lines
Quoted 4 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 204

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+               dev_err(dev, "Cannot read MCU %s firmware version: %d\n", type,
+                       err);  

One line?

I'd like to keep this driver to 80 columns.

Then better to have a logical split then?

			dev_err(dev, "Cannot read MCU %s firmware version: %d\n",
				type, err);

...

Quoted 5 lines
Quoted 4 lines
Quoted 1 line

+ omnia_info_missing_feature(dev, "feature reading");

Tautology. Read the final message. I believe you wanted to pass just "reading" here.

Quoted 9 lines

No, I actually wanted it to print
Your board's MCU firmware does not support the feature reading feature.
as in the feature "feature reading" is not supported.
I guess I could change it to
Your board's MCU firmware does not support the feature reading.
but that would complicate the code: either I would need to add " feature" suffix to all the features[].name, or duplicate the info string from the omnia_info_missing_feature() function.

From point of a mere user (as I am towards this driver) I consider the tautology confusing.

...the 'reading' feature

may be a good compromise.

...

Quoted 11 lines
Quoted 4 lines
Quoted 1 line

+ memcpy(mcu->board_first_mac, &reply[9], ETH_ALEN);

There is an API ether_copy_addr() or so, don't remember by heart. You also need an include for ETH_ALEN definition.

Doc for ether_addr_copy says:
Please note: dst & src must both be aligned to u16.
since the code does:
u16 *a = (u16 *)dst;
const u16 *b = (const u16 *)src;

Quoted 6 lines
  a[0] = b[0];
  a[1] = b[1];
  a[2] = b[2]

Since I am copying from &reply[9], which is not u16-aligned, this won't work.

It would work on architectures that support misaligned accesses, but in general you are right. Perhaps a comment on top to avoid "cleanup" patches like this?

...

Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
include/linux/turris-omnia-mcu-interface.h new file +9 -0
+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)  
Quoted 4 lines
Quoted 2 lines

Keep trailing comma as it might be extended (theoretically). And you do the similar in other enums anyway.

ctl_byt is 8-bit, so this enum really can't be extended.

I understand that (even before writing the previous reply).

Quoted 2 lines

In fact I need
to drop the last comma from omnia_ext_sts_dword_e and omnia_int_e.

Who prevents from having in a new firmware let's say

BIT(31) | BIT(1)

as a new value?

From Linux perspective these are not terminating lines.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#7 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 10 lines · Andy Shevchenko
Quoted 3 lines · Marek Behún
Quoted 1 line · On Tue, 30 Apr 2024 15:53:51 +0300 Andy Shevchenko <[email protected]>…

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 3 lines
Quoted 3 lines
Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader,
+                                 u8 version[static OMNIA_FW_VERSION_HEX_LEN])
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Interesting format of the last parameter. Does it make any difference to the compiler if you use u8 *version?

The compiler will warn if an array with not enough space is passed as argument.

Really?

Indeed:

  extern void a(char *x);

  static void b(char x[static 10]) {
      a(x);
  }

  void c(void) {
      char x[5] = "abcd";
      b(x);
  }

says:
test.c: In function ‘c’:
test.c:9:9: warning: ‘b’ accessing 10 bytes in a region of size 5 [-Wstringop-overflow=]

      9 |         b(x);
        |         ^~~~
  test.c:9:9: note: referencing argument 1 of type ‘char[10]’
  test.c:3:13: note: in a call to function ‘b’
      3 | static void b(char x[static 10]) {
        |

...

Quoted 11 lines
Quoted 6 lines
Quoted 4 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 204

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+               dev_err(dev, "Cannot read MCU %s firmware version: %d\n", type,
+                       err);  

One line?

I'd like to keep this driver to 80 columns.

Then better to have a logical split then?

			dev_err(dev, "Cannot read MCU %s firmware version: %d\n",
				type, err);

OK

Quoted 15 lines
Quoted 5 lines
Quoted 4 lines
Quoted 1 line

+ omnia_info_missing_feature(dev, "feature reading");

Tautology. Read the final message. I believe you wanted to pass just "reading" here.

Quoted 9 lines

No, I actually wanted it to print
Your board's MCU firmware does not support the feature reading feature.
as in the feature "feature reading" is not supported.
I guess I could change it to
Your board's MCU firmware does not support the feature reading.
but that would complicate the code: either I would need to add " feature" suffix to all the features[].name, or duplicate the info string from the omnia_info_missing_feature() function.

Quoted 6 lines

From point of a mere user (as I am towards this driver) I consider the tautology confusing.

...the 'reading' feature

may be a good compromise.

I have rewritten it to use another dev_info:
dev_info(dev,

           "Your board's MCU firmware does not support feature reading.\n");
Quoted 18 lines

...

Quoted 15 lines
Quoted 4 lines
Quoted 1 line

+ memcpy(mcu->board_first_mac, &reply[9], ETH_ALEN);

There is an API ether_copy_addr() or so, don't remember by heart. You also need an include for ETH_ALEN definition.

Doc for ether_addr_copy says:
Please note: dst & src must both be aligned to u16.
since the code does:
u16 *a = (u16 *)dst;
const u16 *b = (const u16 *)src;

  a[0] = b[0];
  a[1] = b[1];
  a[2] = b[2]
Quoted 5 lines
Quoted 2 lines

Since I am copying from &reply[9], which is not u16-aligned, this won't work.

It would work on architectures that support misaligned accesses, but in general you are right. Perhaps a comment on top to avoid "cleanup" patches like this?

OK

Quoted 20 lines
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
include/linux/turris-omnia-mcu-interface.h new file +9 -0
+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)  
Quoted 4 lines
Quoted 2 lines

Keep trailing comma as it might be extended (theoretically). And you do the similar in other enums anyway.

ctl_byt is 8-bit, so this enum really can't be extended.

I understand that (even before writing the previous reply).

Quoted 2 lines

In fact I need
to drop the last comma from omnia_ext_sts_dword_e and omnia_int_e.

Quoted 7 lines

Who prevents from having in a new firmware let's say

BIT(31) | BIT(1)

as a new value?

From Linux perspective these are not terminating lines.

OK

#8 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 5 lines · Marek Behún
Quoted 4 lines · Andy Shevchenko
Quoted 3 lines · Marek Behún
Quoted 1 line · On Tue, 30 Apr 2024 15:53:51 +0300 Andy Shevchenko <[email protected]>…

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 22 lines
Quoted 10 lines
Quoted 8 lines
Quoted 5 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 50

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader,
+                                 u8 version[static OMNIA_FW_VERSION_HEX_LEN])

Interesting format of the last parameter. Does it make any difference to the compiler if you use u8 *version?

The compiler will warn if an array with not enough space is passed as argument.

Really?

Indeed:

  extern void a(char *x);

  static void b(char x[static 10]) {
      a(x);
  }

  void c(void) {
      char x[5] = "abcd";
Quoted 1 line
      b(x);

It's not the example I was talking about. Here should be a(x).

Quoted 11 lines
  }

says:
test.c: In function ‘c’:
test.c:9:9: warning: ‘b’ accessing 10 bytes in a region of size 5 [-Wstringop-overflow=]

      9 |         b(x);
        |         ^~~~
  test.c:9:9: note: referencing argument 1 of type ‘char[10]’
  test.c:3:13: note: in a call to function ‘b’
      3 | static void b(char x[static 10]) {
        |

...

Quoted 18 lines
Quoted 18 lines
Quoted 5 lines
Quoted 4 lines
Quoted 1 line

+ omnia_info_missing_feature(dev, "feature reading");

Tautology. Read the final message. I believe you wanted to pass just "reading" here.

Quoted 9 lines

No, I actually wanted it to print
Your board's MCU firmware does not support the feature reading feature.
as in the feature "feature reading" is not supported.
I guess I could change it to
Your board's MCU firmware does not support the feature reading.
but that would complicate the code: either I would need to add " feature" suffix to all the features[].name, or duplicate the info string from the omnia_info_missing_feature() function.

From point of a mere user (as I am towards this driver) I consider the tautology confusing.

Quoted 7 lines
Quoted 3 lines

...the 'reading' feature

may be a good compromise.

I have rewritten it to use another dev_info:
dev_info(dev,

           "Your board's MCU firmware does not support feature reading.\n");

OK! As long as there are no two messages in a row for the same error.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#9 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 28 lines · Andy Shevchenko
Quoted 5 lines · Marek Behún
Quoted 4 lines · Andy Shevchenko
Quoted 3 lines · Marek Behún
Quoted 1 line · On Tue, 30 Apr 2024 15:53:51 +0300 Andy Shevchenko <[email protected]>…

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 19 lines
Quoted 10 lines
Quoted 8 lines
Quoted 5 lines

drivers/platform/cznic/turris-omnia-mcu-base.c line 50

Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +2 -0
+static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader,
+                                 u8 version[static OMNIA_FW_VERSION_HEX_LEN])

Interesting format of the last parameter. Does it make any difference to the compiler if you use u8 *version?

The compiler will warn if an array with not enough space is passed as argument.

Really?

Indeed:

  extern void a(char *x);

  static void b(char x[static 10]) {
      a(x);
  }
Quoted 6 lines
Quoted 4 lines
  void c(void) {
      char x[5] = "abcd";
      b(x);

It's not the example I was talking about. Here should be a(x).

Somehow I got lost. Let's return to my function, where I have
int omnia_get_version_hash(..., u8 version[static 40]);

and then I use this function:

  u8 version[40];
  omnia_get_version_hash(..., version);

If somehow I made a mistake and declared the version array shorter:
u8 version[20];
omnia_get_version_hash(..., version);
I would get a warning.

So the purpose is to get warned if the compiler can prove that there is not enough space in the destination buffer.

Marek

#10 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 7 lines · Marek Behún
Quoted 6 lines · Andy Shevchenko
Quoted 5 lines · Marek Behún
Quoted 4 lines · Andy Shevchenko
Quoted 3 lines · Marek Behún
Quoted 1 line · On Tue, 30 Apr 2024 15:53:51 +0300 Andy Shevchenko <[email protected]>…

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 31 lines
Quoted 19 lines
Quoted 19 lines
Quoted 10 lines
Quoted 8 lines
Quoted 5 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader,
+                                 u8 version[static OMNIA_FW_VERSION_HEX_LEN])

Interesting format of the last parameter. Does it make any difference to the compiler if you use u8 *version?

The compiler will warn if an array with not enough space is passed as argument.

Really?

Indeed:

  extern void a(char *x);

  static void b(char x[static 10]) {
      a(x);
  }
Quoted 6 lines
Quoted 4 lines
  void c(void) {
      char x[5] = "abcd";
      b(x);

It's not the example I was talking about. Here should be a(x).

Somehow I got lost. Let's return to my function, where I have
int omnia_get_version_hash(..., u8 version[static 40]);

and then I use this function:

Quoted 7 lines
  u8 version[40];
  omnia_get_version_hash(..., version);

If somehow I made a mistake and declared the version array shorter:
u8 version[20];
omnia_get_version_hash(..., version);
I would get a warning.

Yes. Would you get the same warning if you replace the parameter to a pointer?

Quoted 2 lines

So the purpose is to get warned if the compiler can prove that there is not enough space in the destination buffer.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#11 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

Quoted 45 lines · Andy Shevchenko
Quoted 7 lines · Marek Behún
Quoted 6 lines · Andy Shevchenko
Quoted 5 lines · Marek Behún
Quoted 4 lines · Andy Shevchenko
Quoted 3 lines · Marek Behún
Quoted 1 line · On Tue, 30 Apr 2024 15:53:51 +0300 Andy Shevchenko <[email protected]>…

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 34 lines
Quoted 19 lines
Quoted 19 lines
Quoted 10 lines
Quoted 8 lines
Quoted 5 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+static int omnia_get_version_hash(struct omnia_mcu *mcu, bool bootloader,
+                                 u8 version[static OMNIA_FW_VERSION_HEX_LEN])

Interesting format of the last parameter. Does it make any difference to the compiler if you use u8 *version?

The compiler will warn if an array with not enough space is passed as argument.

Really?

Indeed:

  extern void a(char *x);

  static void b(char x[static 10]) {
      a(x);
  }
Quoted 6 lines
Quoted 4 lines
  void c(void) {
      char x[5] = "abcd";
      b(x);

It's not the example I was talking about. Here should be a(x).

Somehow I got lost. Let's return to my function, where I have
int omnia_get_version_hash(..., u8 version[static 40]);

and then I use this function:

  u8 version[40];
  omnia_get_version_hash(..., version);
Quoted 6 lines
Quoted 4 lines

If somehow I made a mistake and declared the version array shorter:
u8 version[20];
omnia_get_version_hash(..., version);
I would get a warning.

Yes. Would you get the same warning if you replace the parameter to a pointer?

If you mean instead of declaring
u8 version[20];
if I did
u8 *version;
omnia_get_version_hash(..., version);
then I will get a different warning:
version is used uninitialized

And if you mean that instead of the
char version[static 40]
in the argument list of the function I used
char *version,
then no, GCC spits no warning.

Marek

#12 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

In reply to Marek Behún
Quoted 5 lines · Marek Behún

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

drivers/platform/cznic/turris-omnia-mcu-base.c line 254

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +10 -0
+	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 */

FEATURES

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +10 -0
+	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);

drivers/platform/cznic/turris-omnia-mcu-base.c line 274

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +10 -0
+			if (ret < 0)
+				return ret;
+
+			mcu->features = ret;
+		} else {
+			mcu->features = le32_to_cpu(reply);
+
+			if (mcu->features & FEAT_FROM_BIT_16_INVALID)
+				mcu->features &= GENMASK(15, 0);
+		}

I'm not a big fan of the inconsistency here when it comes to who handles the endianness, perhaps there is a good reason for that but it looks a bit odd to have it done in a different way for 32-bit and 16-bit.

Quoted 150 lines
drivers/platform/cznic/turris-omnia-mcu-base.c new file +56 -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;
+}
 
+int omnia_cmd_read(const struct i2c_client *client, u8 cmd, void *reply,
+		   unsigned int len);
+
+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 */
include/linux/turris-omnia-mcu-interface.h new file +85 -0
new file mode 100644
index 000000000000..88f8490b5897
@@ -0,0 +1,249 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * CZ.NIC's Turris Omnia MCU I2C interface commands definitions
+ *
+ * 2024 by Marek Behún <[email protected]>
+ */
+
+#ifndef __TURRIS_OMNIA_MCU_INTERFACE_H
+#define __TURRIS_OMNIA_MCU_INTERFACE_H
+
+#include <linux/bitfield.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 USB_OVC_PROT_SETTING bit set in features */
+	CMD_SET_USB_OVC_PROT		= 0x25,
+	CMD_GET_USB_OVC_PROT		= 0x26,
+
+	/* 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 */

include/linux/turris-omnia-mcu-interface.h line 95

Quoted 10 lines
include/linux/turris-omnia-mcu-interface.h new file +10 -0
+	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,
+};

I'm bit worried about many items above, they seem generic enough they could trigger name conflict at some point. Could these all defines be prefixed so there's no risk of collisions.

include/linux/turris-omnia-mcu-interface.h line 101

Quoted 5 lines
include/linux/turris-omnia-mcu-interface.h new file +5 -0
+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,

These are FIELD_PREP(STS_MCU_TYPE_MASK, x), although I suspect you need to use FIELD_PREP_CONST() in this context. If neither ends up working in this context, then leave it as is.

Quoted 22 lines
include/linux/turris-omnia-mcu-interface.h new file +22 -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),

include/linux/turris-omnia-mcu-interface.h line 133

Quoted 10 lines
include/linux/turris-omnia-mcu-interface.h new file +10 -0
+	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,

Ditto.

Quoted 14 lines
include/linux/turris-omnia-mcu-interface.h new file +14 -0
+	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

include/linux/turris-omnia-mcu-interface.h line 157

Quoted 10 lines
include/linux/turris-omnia-mcu-interface.h new file +10 -0
+	 * 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		= 0 << 16,
+	FEAT_MCU_TYPE_GD32		= 1 << 16,
+	FEAT_MCU_TYPE_MKL		= 2 << 16,

Ditto.

Signature · 1 line
 i.
author maintainer
#13 lore raw

Re: [PATCH v8 2/9] platform: cznic: Add preliminary support for Turris Omnia MCU

Thanks, Ilpo, I've applied all your suggestions.

author maintainer
#14 lore raw

PATCH v8 3/9 platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

In reply to Marek Behún

Add support for GPIOs connected to the MCU on the Turris Omnia board.

This includes:
- front button pin
- enable pins for USB regulators
- MiniPCIe / mSATA card presence pins in MiniPCIe port 0
- LED output pins from WAN ethernet PHY, LAN switch and MiniPCIe ports
- on board revisions 32+ also various peripheral resets and another voltage regulator enable pin

---
 .../sysfs-bus-i2c-devices-turris-omnia-mcu    |   16 +
 drivers/platform/cznic/Kconfig                |   15 +
 drivers/platform/cznic/Makefile               |    1 +
 .../platform/cznic/turris-omnia-mcu-base.c    |   33 +-
 .../platform/cznic/turris-omnia-mcu-gpio.c    | 1048 +++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |   69 +-
 6 files changed, 1166 insertions(+), 16 deletions(-)
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-gpio.c
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu +16 -0
index ff5e7cb00206..b27b60d00c87 100644
@@ -22,6 +22,22 @@ Description:	(RO) Contains device first MAC address. Each Turris Omnia is
 
 		Format: %pM.
 
+What:		/sys/bus/i2c/devices/<mcu_device>/front_button_mode
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RW) The front button on the Turris Omnia router can be
+		configured either to change the intensity of all the LEDs on the
+		front panel, or to send the press event to the CPU as an
+		interrupt.
+
+		This file switches between these two modes:
+		- "mcu" makes the button press event be handled by the MCU to
+		  change the LEDs panel intensity.
+		- "cpu" makes the button press event be handled by the CPU.
+
+		Format: %s.
+
 What:		/sys/bus/i2c/devices/<mcu_device>/fw_features
 Date:		July 2024
 KernelVersion:	6.10
drivers/platform/cznic/Kconfig +15 -0
index f8560ff9c1af..3a8c3edcd7e6 100644
@@ -17,9 +17,24 @@ config TURRIS_OMNIA_MCU
 	tristate "Turris Omnia MCU driver"
 	depends on MACH_ARMADA_38X || COMPILE_TEST
 	depends on I2C
+	select GPIOLIB
+	select GPIOLIB_IRQCHIP
 	help
 	  Say Y here to add support for the features implemented by the
 	  microcontroller on the CZ.NIC's Turris Omnia SOHO router.
+	  The features include:
+	  - 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
+	      front LEDs panel brightness)
+	    - to enable / disable USB port voltage regulators and to detect
+	      USB overcurrent
+	    - to detect MiniPCIe / mSATA card presence in MiniPCIe port 0
+	    - to configure resets of various peripherals on board revisions 32+
+	    - to enable / disable the VHV voltage regulator to the SOC in order
+	      to be able to program SOC's OTP on board revisions 32+
+	    - to get input from the LED output pins of the WAN ethernet PHY, LAN
+	      switch and MiniPCIe ports
 	  To compile this driver as a module, choose M here; the module will be
 	  called turris-omnia-mcu.
 
drivers/platform/cznic/Makefile +1 -0
index 31adca73bb94..53fd8f1777a3 100644
@@ -2,3 +2,4 @@
 
 obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
 turris-omnia-mcu-y		:= turris-omnia-mcu-base.o
+turris-omnia-mcu-y		+= turris-omnia-mcu-gpio.o
drivers/platform/cznic/turris-omnia-mcu-base.c +20 -13
index 8893c990853a..708b084cb5da 100644
@@ -22,25 +22,31 @@
 #define OMNIA_FW_VERSION_HEX_LEN	(2 * OMNIA_FW_VERSION_LEN + 1)
 #define OMNIA_BOARD_INFO_LEN		16
 
-int omnia_cmd_read(const struct i2c_client *client, u8 cmd, void *reply,
-		   unsigned int len)
+int omnia_cmd_write_read(const struct i2c_client *client,
+			 void *cmd, unsigned int cmd_len,
+			 void *reply, unsigned int reply_len)
 {
 	struct i2c_msg msgs[2];
-	int ret;
+	int ret, num;
 
 	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));
+	msgs[0].len = cmd_len;
+	msgs[0].buf = cmd;
+	num = 1;
+
+	if (reply_len) {
+		msgs[1].addr = client->addr;
+		msgs[1].flags = I2C_M_RD;
+		msgs[1].len = reply_len;
+		msgs[1].buf = reply;
+		num++;
+	}
+
+	ret = i2c_transfer(client->adapter, msgs, num);
 	if (ret < 0)
 		return ret;
-	if (ret != ARRAY_SIZE(msgs))
+	if (ret != num)
 		return -EIO;
 
 	return 0;
@@ -188,6 +194,7 @@ static const struct attribute_group omnia_mcu_base_group = {
 
 static const struct attribute_group *omnia_mcu_groups[] = {
 	&omnia_mcu_base_group,
+	&omnia_mcu_gpio_group,
 	NULL
 };
 
@@ -353,7 +360,7 @@ static int omnia_mcu_probe(struct i2c_client *client)
 					     "Cannot read board info\n");
 	}
 
-	return 0;
+	return omnia_mcu_register_gpiochip(mcu);
 }
 
 static const struct of_device_id of_omnia_mcu_match[] = {
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +1048 -0

1,048 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +66 -3

89 lines not on this page · raw message

Signature · 1 line
2.43.2
#15 lore raw

Re: [PATCH v8 3/9] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 10 lines · Marek Behún

Add support for GPIOs connected to the MCU on the Turris Omnia board.

This includes:
- front button pin
- enable pins for USB regulators
- MiniPCIe / mSATA card presence pins in MiniPCIe port 0
- LED output pins from WAN ethernet PHY, LAN switch and MiniPCIe ports
- on board revisions 32+ also various peripheral resets and another voltage regulator enable pin

...

Quoted 30 lines
drivers/platform/cznic/turris-omnia-mcu-base.c +14 -11
-int omnia_cmd_read(const struct i2c_client *client, u8 cmd, void *reply,
-                  unsigned int len)
+int omnia_cmd_write_read(const struct i2c_client *client,
+                        void *cmd, unsigned int cmd_len,
+                        void *reply, unsigned int reply_len)
 {
        struct i2c_msg msgs[2];
-       int ret;
+       int ret, num;
 
        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));
+       msgs[0].len = cmd_len;
+       msgs[0].buf = cmd;
+       num = 1;
+
+       if (reply_len) {
+               msgs[1].addr = client->addr;
+               msgs[1].flags = I2C_M_RD;
+               msgs[1].len = reply_len;
+               msgs[1].buf = reply;
+               num++;

drivers/platform/cznic/turris-omnia-mcu-base.c line 52

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-base.c +4 -1
+       }
+
+       ret = i2c_transfer(client->adapter, msgs, num);
        if (ret < 0)
                return ret;
-       if (ret != ARRAY_SIZE(msgs))
+       if (ret != num)
                return -EIO;
 
        return 0;

Hold on, you are "patching" the code you just brought by the previous patch?! No, just do from the beginning how it should be at the end.

...

Quoted 1 line

+#include <linux/devm-helpers.h>

Do you still need this?

...

Quoted 1 line

+#define FRONT_BUTTON_RELEASE_DELAY 50 /* ms */

Use proper unit suffix instead of a comment like many others do.

_MS here.

...

Quoted 32 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +32 -0
+static const char * const omnia_mcu_gpio_templates[64] = {
+       /* GPIOs with value read from the 16-bit wide status */
+       [4]  = "gpio%u.MiniPCIe0 Card Detect",
+       [5]  = "gpio%u.MiniPCIe0 mSATA Indicator",
+       [6]  = "gpio%u.Front USB3 port over-current",
+       [7]  = "gpio%u.Rear USB3 port over-current",
+       [8]  = "gpio%u.Front USB3 port power",
+       [9]  = "gpio%u.Rear USB3 port power",
+       [12] = "gpio%u.Front Button",
+
+       /* GPIOs with value read from the 32-bit wide extended status */
+       [16] = "gpio%u.SFP nDET",
+       [28] = "gpio%u.MiniPCIe0 LED",
+       [29] = "gpio%u.MiniPCIe1 LED",
+       [30] = "gpio%u.MiniPCIe2 LED",
+       [31] = "gpio%u.MiniPCIe0 PAN LED",
+       [32] = "gpio%u.MiniPCIe1 PAN LED",
+       [33] = "gpio%u.MiniPCIe2 PAN LED",
+       [34] = "gpio%u.WAN PHY LED0",
+       [35] = "gpio%u.WAN PHY LED1",
+       [36] = "gpio%u.LAN switch p0 LED0",
+       [37] = "gpio%u.LAN switch p0 LED1",
+       [38] = "gpio%u.LAN switch p1 LED0",
+       [39] = "gpio%u.LAN switch p1 LED1",
+       [40] = "gpio%u.LAN switch p2 LED0",
+       [41] = "gpio%u.LAN switch p2 LED1",
+       [42] = "gpio%u.LAN switch p3 LED0",
+       [43] = "gpio%u.LAN switch p3 LED1",
+       [44] = "gpio%u.LAN switch p4 LED0",
+       [45] = "gpio%u.LAN switch p4 LED1",
+       [46] = "gpio%u.LAN switch p5 LED0",
+       [47] = "gpio%u.LAN switch p5 LED1",

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 71

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10 -0
+
+       /* GPIOs with value read from the 16-bit wide extended control status */
+       [48] = "gpio%u.eMMC nRESET",
+       [49] = "gpio%u.LAN switch nRESET",
+       [50] = "gpio%u.WAN PHY nRESET",
+       [51] = "gpio%u.MiniPCIe0 nPERST",
+       [52] = "gpio%u.MiniPCIe1 nPERST",
+       [53] = "gpio%u.MiniPCIe2 nPERST",
+       [54] = "gpio%u.WAN PHY SFP mux",
+};

You may reduce the memory footprint of these just by doing "gpio%u." part(s) outside. Here compiler won't compress this (as in the case of repetitive string literals),

...

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 112

Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6 -0
+static const struct omnia_gpio {
+       u8 cmd, ctl_cmd;
+       u32 bit, ctl_bit;
+       u32 int_bit;
+       u16 feat, feat_mask;
+} omnia_gpios[64] = {

It's much better to decouple definition and assignment and put definition _before_ the macros that fill it.

Quoted 1 line

+};

...

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 257

Quoted 7 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +7 -0
+               scoped_guard(mutex, &mcu->lock)
+                       val = omnia_cmd_read_bit(mcu->client,
+                                                CMD_GET_EXT_CONTROL_STATUS,
+                                                EXT_CTL_PHY_SFP_AUTO);
+
+               if (val < 0)
+                       return val;

I would move that under guard for the sake of better readability (usual pattern in place). It's anyway a slow path and one branch under the mutex won't affect anything.

Quoted 4 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +4 -0
+               if (val)
+                       return GPIO_LINE_DIRECTION_IN;
+
+               return GPIO_LINE_DIRECTION_OUT;

...

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 342

Quoted 7 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6 -0
+       struct omnia_mcu *mcu = gpiochip_get_data(gc);
+       u32 sts_bits, ext_sts_bits, ext_ctl_bits;
+       int err, i;
 
+       sts_bits = 0;
+       ext_sts_bits = 0;
+       ext_ctl_bits = 0;

Why not assign these inside the definition line?

...

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 388

Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6 -0
+       for_each_set_bit(i, mask, ARRAY_SIZE(omnia_gpios)) {
+               if (omnia_gpios[i].cmd == CMD_GET_STATUS_WORD)
+                       __assign_bit(i, bits, sts_bits & omnia_gpios[i].bit);
+               else if (omnia_gpios[i].cmd == CMD_GET_EXT_STATUS_DWORD)
+                       __assign_bit(i, bits, ext_sts_bits &
+                                             omnia_gpios[i].bit);

One line?

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 391

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +3 -0
+               else if (omnia_gpios[i].cmd == CMD_GET_EXT_CONTROL_STATUS)
+                       __assign_bit(i, bits, ext_ctl_bits &
+                                             omnia_gpios[i].bit);

Ditto?

Quoted 1 line

+ }

...

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 423

Quoted 9 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +9 -0
+       struct omnia_mcu *mcu = gpiochip_get_data(gc);
+       u16 ext_ctl, ext_ctl_mask;
+       u8 ctl, ctl_mask;
+       int i;
+
+       ctl = 0;
+       ctl_mask = 0;
+       ext_ctl = 0;
+       ext_ctl_mask = 0;

Assignments in the definition line?

...

Quoted 11 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +11 -0
+       for_each_set_bit(i, mask, ARRAY_SIZE(omnia_gpios)) {
+               if (omnia_gpios[i].ctl_cmd == CMD_GENERAL_CONTROL) {
+                       ctl_mask |= omnia_gpios[i].ctl_bit;
+                       if (test_bit(i, bits))
+                               ctl |= omnia_gpios[i].ctl_bit;
+               } else if (omnia_gpios[i].ctl_cmd == CMD_EXT_CONTROL) {
+                       ext_ctl_mask |= omnia_gpios[i].ctl_bit;
+                       if (test_bit(i, bits))
+                               ext_ctl |= omnia_gpios[i].ctl_bit;
+               }
+       }

...

Quoted 5 lines

+/**
+ * omnia_mask_interleave - Interleaves the bytes from @rising and @falling

+ *     @dst: the destination u8 array of interleaved bytes
+ *     @rising: rising mask
+ *     @falling: falling mask
Quoted 7 lines

+ *
+ * Interleaves the little-endian bytes from @rising and @falling words.
+ *
+ * If @rising = (r0, r1, r2, r3) and @falling = (f0, f1, f2, f3), the result is
+ * @dst = (r0, f0, r1, f1, r2, f2, r3, f3).
+ *
+ * The MCU receives interrupt mask and reports pending interrupt bitmap int this

an interrupt
a pending
int --> in ?

Quoted 8 lines

+ * interleaved format. The rationale behind it is that the low-indexed bits are
+ * more important - in many cases, the user will be interested only in
+ * interrupts with indexes 0 to 7, and so the system can stop reading after
+ * first 2 bytes (r0, f0), to save time on the slow I2C bus.
+ *
+ * Feel free to remove this function and its inverse, omnia_mask_deinterleave,
+ * and use an appropriate bitmap_* function once such a function exists.
+ */

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 605

Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6 -0
+static void omnia_mask_interleave(u8 *dst, u32 rising, u32 falling)
+{
+       for (int i = 0; i < sizeof(u32); ++i) {
+               dst[2 * i] = rising >> (8 * i);
+               dst[2 * i + 1] = falling >> (8 * i);
+       }

I will look at this later on,

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 624

Quoted 11 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10 -0
+}
 
+static void omnia_mask_deinterleave(const u8 *src, u32 *rising, u32 *falling)
+{
+       *rising = *falling = 0;
+
+       for (int i = 0; i < sizeof(u32); ++i) {
+               *rising |= src[2 * i] << (8 * i);
+               *falling |= src[2 * i + 1] << (8 * i);
+       }
+}

and into this.

...

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 722

Quoted 12 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +12 -0
+static size_t omnia_irq_compute_pending_length(u32 rising, u32 falling)
+{
+       size_t rlen = 0, flen = 0;
+
+       if (rising)
+               rlen = ((__fls(rising) >> 3) << 1) + 1;
+
+       if (falling)
+               flen = ((__fls(falling) >> 3) << 1) + 2;
+
+       return max(rlen, flen);
+}

I am not sure why you need this, but it can be done easily

x = ((__fls(falling | rising) >> 3) << 1) + 1;
if (falling)
return x + 1;
return x;

and most likely you can drop minmax.h.

...

Quoted 1 line

+static const char * const front_button_modes[2] = { "mcu", "cpu" };

2 is not needed.

...

Quoted 1 line

-#include <linux/i2c.h>

??? That is exactly the point to have things done from the beginning.

Quoted 7 lines
drivers/platform/cznic/turris-omnia-mcu.h +4 -0
+#include <linux/bitops.h>
+#include <linux/gpio/driver.h>
 #include <linux/if_ether.h>
+#include <linux/mutex.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 #include <asm/byteorder.h>

...

Quoted 1 line

+ err = omnia_cmd_read(client, cmd, &reply, (__fls(bits) >> 3) + 1);

Perhaps a helper for this (__fls(x) >> 3 + (y)) ? It seems it's used in a few places.

Review

Quoted 2 lines
(quoted diff) +2 -0
+       if (err)
+               return err;

--
With Best Regards,
Andy Shevchenko

author maintainer
#16 lore raw

Re: [PATCH v8 3/9] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 53 lines · Andy Shevchenko
Quoted 10 lines · Marek Behún

Add support for GPIOs connected to the MCU on the Turris Omnia board.

This includes:
- front button pin
- enable pins for USB regulators
- MiniPCIe / mSATA card presence pins in MiniPCIe port 0
- LED output pins from WAN ethernet PHY, LAN switch and MiniPCIe ports
- on board revisions 32+ also various peripheral resets and another voltage regulator enable pin

...

Quoted 39 lines
drivers/platform/cznic/turris-omnia-mcu-base.c +18 -12
-int omnia_cmd_read(const struct i2c_client *client, u8 cmd, void *reply,
-                  unsigned int len)
+int omnia_cmd_write_read(const struct i2c_client *client,
+                        void *cmd, unsigned int cmd_len,
+                        void *reply, unsigned int reply_len)
 {
        struct i2c_msg msgs[2];
-       int ret;
+       int ret, num;
 
        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));
+       msgs[0].len = cmd_len;
+       msgs[0].buf = cmd;
+       num = 1;
+
+       if (reply_len) {
+               msgs[1].addr = client->addr;
+               msgs[1].flags = I2C_M_RD;
+               msgs[1].len = reply_len;
+               msgs[1].buf = reply;
+               num++;
+       }
+
+       ret = i2c_transfer(client->adapter, msgs, num);
        if (ret < 0)
                return ret;
-       if (ret != ARRAY_SIZE(msgs))
+       if (ret != num)
                return -EIO;
Quoted 4 lines
Quoted 1 line
        return 0;

Hold on, you are "patching" the code you just brought by the previous patch?! No, just do from the beginning how it should be at the end.

Fixed.

Quoted 3 lines
Quoted 1 line

+#include <linux/devm-helpers.h>

Do you still need this?

Yes, for devm_delayed_work_drop().

Quoted 7 lines

...

Quoted 1 line

+#define FRONT_BUTTON_RELEASE_DELAY 50 /* ms */

Use proper unit suffix instead of a comment like many others do.

_MS here.

Fixed.

Quoted 38 lines
Quoted 38 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +38 -0
+static const char * const omnia_mcu_gpio_templates[64] = {
+       /* GPIOs with value read from the 16-bit wide status */
+       [4]  = "gpio%u.MiniPCIe0 Card Detect",
+       [5]  = "gpio%u.MiniPCIe0 mSATA Indicator",
+       [6]  = "gpio%u.Front USB3 port over-current",
+       [7]  = "gpio%u.Rear USB3 port over-current",
+       [8]  = "gpio%u.Front USB3 port power",
+       [9]  = "gpio%u.Rear USB3 port power",
+       [12] = "gpio%u.Front Button",
+
+       /* GPIOs with value read from the 32-bit wide extended status */
+       [16] = "gpio%u.SFP nDET",
+       [28] = "gpio%u.MiniPCIe0 LED",
+       [29] = "gpio%u.MiniPCIe1 LED",
+       [30] = "gpio%u.MiniPCIe2 LED",
+       [31] = "gpio%u.MiniPCIe0 PAN LED",
+       [32] = "gpio%u.MiniPCIe1 PAN LED",
+       [33] = "gpio%u.MiniPCIe2 PAN LED",
+       [34] = "gpio%u.WAN PHY LED0",
+       [35] = "gpio%u.WAN PHY LED1",
+       [36] = "gpio%u.LAN switch p0 LED0",
+       [37] = "gpio%u.LAN switch p0 LED1",
+       [38] = "gpio%u.LAN switch p1 LED0",
+       [39] = "gpio%u.LAN switch p1 LED1",
+       [40] = "gpio%u.LAN switch p2 LED0",
+       [41] = "gpio%u.LAN switch p2 LED1",
+       [42] = "gpio%u.LAN switch p3 LED0",
+       [43] = "gpio%u.LAN switch p3 LED1",
+       [44] = "gpio%u.LAN switch p4 LED0",
+       [45] = "gpio%u.LAN switch p4 LED1",
+       [46] = "gpio%u.LAN switch p5 LED0",
+       [47] = "gpio%u.LAN switch p5 LED1",
+
+       /* GPIOs with value read from the 16-bit wide extended control status */
+       [48] = "gpio%u.eMMC nRESET",
+       [49] = "gpio%u.LAN switch nRESET",
+       [50] = "gpio%u.WAN PHY nRESET",
+       [51] = "gpio%u.MiniPCIe0 nPERST",
Quoted 8 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 71

Quoted 4 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +4 -0
+       [52] = "gpio%u.MiniPCIe1 nPERST",
+       [53] = "gpio%u.MiniPCIe2 nPERST",
+       [54] = "gpio%u.WAN PHY SFP mux",
+};

You may reduce the memory footprint of these just by doing "gpio%u." part(s) outside. Here compiler won't compress this (as in the case of repetitive string literals),

Are you saying that I should dynamically create another array just to pass it to the gpiochip's names pointer?

Quoted 9 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 112

Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6 -0
+static const struct omnia_gpio {
+       u8 cmd, ctl_cmd;
+       u32 bit, ctl_bit;
+       u32 int_bit;
+       u16 feat, feat_mask;
+} omnia_gpios[64] = {

It's much better to decouple definition and assignment and put definition _before_ the macros that fill it.

Fixed.

Quoted 11 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 257

Quoted 7 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +7 -0
+               scoped_guard(mutex, &mcu->lock)
+                       val = omnia_cmd_read_bit(mcu->client,
+                                                CMD_GET_EXT_CONTROL_STATUS,
+                                                EXT_CTL_PHY_SFP_AUTO);
+
+               if (val < 0)
+                       return val;

I would move that under guard for the sake of better readability (usual pattern in place). It's anyway a slow path and one branch under the mutex won't affect anything.

OK.

Quoted 11 lines
Quoted 4 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +4 -0
+               if (val)
+                       return GPIO_LINE_DIRECTION_IN;
+
+               return GPIO_LINE_DIRECTION_OUT;

...

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +3 -0
+       struct omnia_mcu *mcu = gpiochip_get_data(gc);
+       u32 sts_bits, ext_sts_bits, ext_ctl_bits;
+       int err, i;
Quoted 5 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 342

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +3 -0
+       sts_bits = 0;
+       ext_sts_bits = 0;
+       ext_ctl_bits = 0;

Why not assign these inside the definition line?

OK.

Quoted 8 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 388

Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6 -0
+       for_each_set_bit(i, mask, ARRAY_SIZE(omnia_gpios)) {
+               if (omnia_gpios[i].cmd == CMD_GET_STATUS_WORD)
+                       __assign_bit(i, bits, sts_bits & omnia_gpios[i].bit);
+               else if (omnia_gpios[i].cmd == CMD_GET_EXT_STATUS_DWORD)
+                       __assign_bit(i, bits, ext_sts_bits &
+                                             omnia_gpios[i].bit);

One line?

That would be 81 columns, which I would like to avoid.
I can remove the _bits suffix from these variables, though. What do you think?

Quoted 20 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 391

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +3 -0
+               else if (omnia_gpios[i].cmd == CMD_GET_EXT_CONTROL_STATUS)
+                       __assign_bit(i, bits, ext_ctl_bits &
+                                             omnia_gpios[i].bit);

Ditto?

Quoted 1 line

+ }

...

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 423

Quoted 9 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +9 -0
+       struct omnia_mcu *mcu = gpiochip_get_data(gc);
+       u16 ext_ctl, ext_ctl_mask;
+       u8 ctl, ctl_mask;
+       int i;
+
+       ctl = 0;
+       ctl_mask = 0;
+       ext_ctl = 0;
+       ext_ctl_mask = 0;
Quoted 1 line

Assignments in the definition line?

OK

Quoted 27 lines
Quoted 11 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +11 -0
+       for_each_set_bit(i, mask, ARRAY_SIZE(omnia_gpios)) {
+               if (omnia_gpios[i].ctl_cmd == CMD_GENERAL_CONTROL) {
+                       ctl_mask |= omnia_gpios[i].ctl_bit;
+                       if (test_bit(i, bits))
+                               ctl |= omnia_gpios[i].ctl_bit;
+               } else if (omnia_gpios[i].ctl_cmd == CMD_EXT_CONTROL) {
+                       ext_ctl_mask |= omnia_gpios[i].ctl_bit;
+                       if (test_bit(i, bits))
+                               ext_ctl |= omnia_gpios[i].ctl_bit;
+               }
+       }

...

Quoted 5 lines

+/**
+ * omnia_mask_interleave - Interleaves the bytes from @rising and @falling

+ *     @dst: the destination u8 array of interleaved bytes
+ *     @rising: rising mask
+ *     @falling: falling mask
Quoted 7 lines

+ *
+ * Interleaves the little-endian bytes from @rising and @falling words.
+ *
+ * If @rising = (r0, r1, r2, r3) and @falling = (f0, f1, f2, f3), the result is
+ * @dst = (r0, f0, r1, f1, r2, f2, r3, f3).
+ *
+ * The MCU receives interrupt mask and reports pending interrupt bitmap int this

Quoted 3 lines

an interrupt
a pending
int --> in ?

Thx.

Quoted 48 lines
Quoted 8 lines

+ * interleaved format. The rationale behind it is that the low-indexed bits are
+ * more important - in many cases, the user will be interested only in
+ * interrupts with indexes 0 to 7, and so the system can stop reading after
+ * first 2 bytes (r0, f0), to save time on the slow I2C bus.
+ *
+ * Feel free to remove this function and its inverse, omnia_mask_deinterleave,
+ * and use an appropriate bitmap_* function once such a function exists.
+ */

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 605

Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6 -0
+static void omnia_mask_interleave(u8 *dst, u32 rising, u32 falling)
+{
+       for (int i = 0; i < sizeof(u32); ++i) {
+               dst[2 * i] = rising >> (8 * i);
+               dst[2 * i + 1] = falling >> (8 * i);
+       }

I will look at this later on,

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 624

Quoted 11 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10 -0
+}
 
+static void omnia_mask_deinterleave(const u8 *src, u32 *rising, u32 *falling)
+{
+       *rising = *falling = 0;
+
+       for (int i = 0; i < sizeof(u32); ++i) {
+               *rising |= src[2 * i] << (8 * i);
+               *falling |= src[2 * i + 1] << (8 * i);
+       }
+}

and into this.

...

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 722

Quoted 12 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +12 -0
+static size_t omnia_irq_compute_pending_length(u32 rising, u32 falling)
+{
+       size_t rlen = 0, flen = 0;
+
+       if (rising)
+               rlen = ((__fls(rising) >> 3) << 1) + 1;
+
+       if (falling)
+               flen = ((__fls(falling) >> 3) << 1) + 2;
+
+       return max(rlen, flen);
+}

I am not sure why you need this, but it can be done easily

Quoted 6 lines

x = ((__fls(falling | rising) >> 3) << 1) + 1;
if (falling)
return x + 1;
return x;

and most likely you can drop minmax.h.

This will return different results for for example when
rising = 0x100
falling = 0x10
where we need to read only 3 bytes, but your version will say that we need 4 bytes.

Quoted 3 lines
Quoted 1 line

+static const char * const front_button_modes[2] = { "mcu", "cpu" };

2 is not needed.

OK

Quoted 3 lines
Quoted 1 line

-#include <linux/i2c.h>

??? That is exactly the point to have things done from the beginning.

I must have somehow missed this before sending, I see that I've already fixed it in my working branch.

Quoted 22 lines
Quoted 7 lines
drivers/platform/cznic/turris-omnia-mcu.h +4 -0
+#include <linux/bitops.h>
+#include <linux/gpio/driver.h>
 #include <linux/if_ether.h>
+#include <linux/mutex.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 #include <asm/byteorder.h>

...

Quoted 1 line

+ err = omnia_cmd_read(client, cmd, &reply, (__fls(bits) >> 3) + 1);

Perhaps a helper for this (__fls(x) >> 3 + (y)) ? It seems it's used in a few places.

Review

Quoted 2 lines
(quoted diff) +2 -0
+       if (err)
+               return err;

--
With Best Regards,
Andy Shevchenko

#17 lore raw

Re: [PATCH v8 3/9] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 2 lines · Marek Behún
Quoted 1 line · Andy Shevchenko

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 47 lines
Quoted 38 lines
Quoted 38 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +38 -0
+static const char * const omnia_mcu_gpio_templates[64] = {
+       /* GPIOs with value read from the 16-bit wide status */
+       [4]  = "gpio%u.MiniPCIe0 Card Detect",
+       [5]  = "gpio%u.MiniPCIe0 mSATA Indicator",
+       [6]  = "gpio%u.Front USB3 port over-current",
+       [7]  = "gpio%u.Rear USB3 port over-current",
+       [8]  = "gpio%u.Front USB3 port power",
+       [9]  = "gpio%u.Rear USB3 port power",
+       [12] = "gpio%u.Front Button",
+
+       /* GPIOs with value read from the 32-bit wide extended status */
+       [16] = "gpio%u.SFP nDET",
+       [28] = "gpio%u.MiniPCIe0 LED",
+       [29] = "gpio%u.MiniPCIe1 LED",
+       [30] = "gpio%u.MiniPCIe2 LED",
+       [31] = "gpio%u.MiniPCIe0 PAN LED",
+       [32] = "gpio%u.MiniPCIe1 PAN LED",
+       [33] = "gpio%u.MiniPCIe2 PAN LED",
+       [34] = "gpio%u.WAN PHY LED0",
+       [35] = "gpio%u.WAN PHY LED1",
+       [36] = "gpio%u.LAN switch p0 LED0",
+       [37] = "gpio%u.LAN switch p0 LED1",
+       [38] = "gpio%u.LAN switch p1 LED0",
+       [39] = "gpio%u.LAN switch p1 LED1",
+       [40] = "gpio%u.LAN switch p2 LED0",
+       [41] = "gpio%u.LAN switch p2 LED1",
+       [42] = "gpio%u.LAN switch p3 LED0",
+       [43] = "gpio%u.LAN switch p3 LED1",
+       [44] = "gpio%u.LAN switch p4 LED0",
+       [45] = "gpio%u.LAN switch p4 LED1",
+       [46] = "gpio%u.LAN switch p5 LED0",
+       [47] = "gpio%u.LAN switch p5 LED1",
+
+       /* GPIOs with value read from the 16-bit wide extended control status */
+       [48] = "gpio%u.eMMC nRESET",
+       [49] = "gpio%u.LAN switch nRESET",
+       [50] = "gpio%u.WAN PHY nRESET",
+       [51] = "gpio%u.MiniPCIe0 nPERST",
Quoted 8 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 71

Quoted 4 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +4 -0
+       [52] = "gpio%u.MiniPCIe1 nPERST",
+       [53] = "gpio%u.MiniPCIe2 nPERST",
+       [54] = "gpio%u.WAN PHY SFP mux",
+};

You may reduce the memory footprint of these just by doing "gpio%u." part(s) outside. Here compiler won't compress this (as in the case of repetitive string literals),

Quoted 2 lines

Are you saying that I should dynamically create another array just to pass it to the gpiochip's names pointer?

I have looked into this again and now I'm puzzled how you tested this. To me it seems that those gpio%u will go as a fixed string to the user space, there is no %u --> number substitution happens. Moreover, this data anyway is redundant. Userspace and debugfs all have line numbers being printed.

...

Quoted 10 lines
Quoted 8 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 388

Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6 -0
+       for_each_set_bit(i, mask, ARRAY_SIZE(omnia_gpios)) {
+               if (omnia_gpios[i].cmd == CMD_GET_STATUS_WORD)
+                       __assign_bit(i, bits, sts_bits & omnia_gpios[i].bit);
+               else if (omnia_gpios[i].cmd == CMD_GET_EXT_STATUS_DWORD)
+                       __assign_bit(i, bits, ext_sts_bits &
+                                             omnia_gpios[i].bit);

One line?

That would be 81 columns, which I would like to avoid.

81?! It's fine! Even documentation allows that for the readability.

Quoted 2 lines

I can remove the _bits suffix from these variables, though. What do you think?

Make sense as well.

Quoted 7 lines
Quoted 7 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 391

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +3 -0
+               else if (omnia_gpios[i].cmd == CMD_GET_EXT_CONTROL_STATUS)
+                       __assign_bit(i, bits, ext_ctl_bits &
+                                             omnia_gpios[i].bit);

Ditto?

Quoted 1 line

+ }

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#18 lore raw

Re: [PATCH v8 3/9] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 53 lines · Andy Shevchenko
Quoted 2 lines · Marek Behún
Quoted 1 line · Andy Shevchenko

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 47 lines
Quoted 46 lines
Quoted 32 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +32 -0
+static const char * const omnia_mcu_gpio_templates[64] = {
+       /* GPIOs with value read from the 16-bit wide status */
+       [4]  = "gpio%u.MiniPCIe0 Card Detect",
+       [5]  = "gpio%u.MiniPCIe0 mSATA Indicator",
+       [6]  = "gpio%u.Front USB3 port over-current",
+       [7]  = "gpio%u.Rear USB3 port over-current",
+       [8]  = "gpio%u.Front USB3 port power",
+       [9]  = "gpio%u.Rear USB3 port power",
+       [12] = "gpio%u.Front Button",
+
+       /* GPIOs with value read from the 32-bit wide extended status */
+       [16] = "gpio%u.SFP nDET",
+       [28] = "gpio%u.MiniPCIe0 LED",
+       [29] = "gpio%u.MiniPCIe1 LED",
+       [30] = "gpio%u.MiniPCIe2 LED",
+       [31] = "gpio%u.MiniPCIe0 PAN LED",
+       [32] = "gpio%u.MiniPCIe1 PAN LED",
+       [33] = "gpio%u.MiniPCIe2 PAN LED",
+       [34] = "gpio%u.WAN PHY LED0",
+       [35] = "gpio%u.WAN PHY LED1",
+       [36] = "gpio%u.LAN switch p0 LED0",
+       [37] = "gpio%u.LAN switch p0 LED1",
+       [38] = "gpio%u.LAN switch p1 LED0",
+       [39] = "gpio%u.LAN switch p1 LED1",
+       [40] = "gpio%u.LAN switch p2 LED0",
+       [41] = "gpio%u.LAN switch p2 LED1",
+       [42] = "gpio%u.LAN switch p3 LED0",
+       [43] = "gpio%u.LAN switch p3 LED1",
+       [44] = "gpio%u.LAN switch p4 LED0",
+       [45] = "gpio%u.LAN switch p4 LED1",
+       [46] = "gpio%u.LAN switch p5 LED0",
+       [47] = "gpio%u.LAN switch p5 LED1",

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 71

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10 -0
+
+       /* GPIOs with value read from the 16-bit wide extended control status */
+       [48] = "gpio%u.eMMC nRESET",
+       [49] = "gpio%u.LAN switch nRESET",
+       [50] = "gpio%u.WAN PHY nRESET",
+       [51] = "gpio%u.MiniPCIe0 nPERST",
+       [52] = "gpio%u.MiniPCIe1 nPERST",
+       [53] = "gpio%u.MiniPCIe2 nPERST",
+       [54] = "gpio%u.WAN PHY SFP mux",
+};

You may reduce the memory footprint of these just by doing "gpio%u." part(s) outside. Here compiler won't compress this (as in the case of repetitive string literals),

Quoted 8 lines
Quoted 2 lines

Are you saying that I should dynamically create another array just to pass it to the gpiochip's names pointer?

I have looked into this again and now I'm puzzled how you tested this. To me it seems that those gpio%u will go as a fixed string to the user space, there is no %u --> number substitution happens. Moreover, this data anyway is redundant. Userspace and debugfs all have line numbers being printed.

It gets substituted in drivers/gpio/gpiolib-sysfs.c, function gpiod_export():

dev = device_create_with_groups(&gpio_class, &gdev->dev,

                                  MKDEV(0, 0), data, gpio_groups,
				  ioname ? ioname : "gpio%u",
				  desc_to_gpio(desc));

The ioname variable contains the string.

This is then visible in sysfs:

  $ cd /sys/class/gpio
  $ echo 560 >export
  $ ls
  ...
  gpio560.eMMC nRESET
  ...
Quoted 9 lines

...

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6 -0
+       for_each_set_bit(i, mask, ARRAY_SIZE(omnia_gpios)) {
+               if (omnia_gpios[i].cmd == CMD_GET_STATUS_WORD)
+                       __assign_bit(i, bits, sts_bits & omnia_gpios[i].bit);
+               else if (omnia_gpios[i].cmd == CMD_GET_EXT_STATUS_DWORD)
+                       __assign_bit(i, bits, ext_sts_bits &
+                                             omnia_gpios[i].bit);
Quoted 5 lines
Quoted 3 lines
Quoted 1 line

One line?

That would be 81 columns, which I would like to avoid.

81?! It's fine! Even documentation allows that for the readability.

OK

Quoted 18 lines
Quoted 2 lines

I can remove the _bits suffix from these variables, though. What do you think?

Make sense as well.

Quoted 7 lines
Quoted 7 lines

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 391

Quoted 3 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +3 -0
+               else if (omnia_gpios[i].cmd == CMD_GET_EXT_CONTROL_STATUS)
+                       __assign_bit(i, bits, ext_ctl_bits &
+                                             omnia_gpios[i].bit);

Ditto?

Quoted 1 line

+ }

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#19 lore raw

Re: [PATCH v8 3/9] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 4 lines · Marek Behún
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Marek Behún
Quoted 1 line · Andy Shevchenko

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 66 lines
Quoted 47 lines
Quoted 47 lines
Quoted 46 lines
Quoted 32 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +32 -0
+static const char * const omnia_mcu_gpio_templates[64] = {
+       /* GPIOs with value read from the 16-bit wide status */
+       [4]  = "gpio%u.MiniPCIe0 Card Detect",
+       [5]  = "gpio%u.MiniPCIe0 mSATA Indicator",
+       [6]  = "gpio%u.Front USB3 port over-current",
+       [7]  = "gpio%u.Rear USB3 port over-current",
+       [8]  = "gpio%u.Front USB3 port power",
+       [9]  = "gpio%u.Rear USB3 port power",
+       [12] = "gpio%u.Front Button",
+
+       /* GPIOs with value read from the 32-bit wide extended status */
+       [16] = "gpio%u.SFP nDET",
+       [28] = "gpio%u.MiniPCIe0 LED",
+       [29] = "gpio%u.MiniPCIe1 LED",
+       [30] = "gpio%u.MiniPCIe2 LED",
+       [31] = "gpio%u.MiniPCIe0 PAN LED",
+       [32] = "gpio%u.MiniPCIe1 PAN LED",
+       [33] = "gpio%u.MiniPCIe2 PAN LED",
+       [34] = "gpio%u.WAN PHY LED0",
+       [35] = "gpio%u.WAN PHY LED1",
+       [36] = "gpio%u.LAN switch p0 LED0",
+       [37] = "gpio%u.LAN switch p0 LED1",
+       [38] = "gpio%u.LAN switch p1 LED0",
+       [39] = "gpio%u.LAN switch p1 LED1",
+       [40] = "gpio%u.LAN switch p2 LED0",
+       [41] = "gpio%u.LAN switch p2 LED1",
+       [42] = "gpio%u.LAN switch p3 LED0",
+       [43] = "gpio%u.LAN switch p3 LED1",
+       [44] = "gpio%u.LAN switch p4 LED0",
+       [45] = "gpio%u.LAN switch p4 LED1",
+       [46] = "gpio%u.LAN switch p5 LED0",
+       [47] = "gpio%u.LAN switch p5 LED1",

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 71

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10 -0
+
+       /* GPIOs with value read from the 16-bit wide extended control status */
+       [48] = "gpio%u.eMMC nRESET",
+       [49] = "gpio%u.LAN switch nRESET",
+       [50] = "gpio%u.WAN PHY nRESET",
+       [51] = "gpio%u.MiniPCIe0 nPERST",
+       [52] = "gpio%u.MiniPCIe1 nPERST",
+       [53] = "gpio%u.MiniPCIe2 nPERST",
+       [54] = "gpio%u.WAN PHY SFP mux",
+};

You may reduce the memory footprint of these just by doing "gpio%u." part(s) outside. Here compiler won't compress this (as in the case of repetitive string literals),

Quoted 8 lines
Quoted 2 lines

Are you saying that I should dynamically create another array just to pass it to the gpiochip's names pointer?

I have looked into this again and now I'm puzzled how you tested this. To me it seems that those gpio%u will go as a fixed string to the user space, there is no %u --> number substitution happens. Moreover, this data anyway is redundant. Userspace and debugfs all have line numbers being printed.

It gets substituted in drivers/gpio/gpiolib-sysfs.c, function gpiod_export():

dev = device_create_with_groups(&gpio_class, &gdev->dev,

                                  MKDEV(0, 0), data, gpio_groups,
                                  ioname ? ioname : "gpio%u",
                                  desc_to_gpio(desc));

The ioname variable contains the string.

Quoted 8 lines

This is then visible in sysfs:

  $ cd /sys/class/gpio
  $ echo 560 >export
  $ ls
  ...
  gpio560.eMMC nRESET
  ...

Interesting. But before giving my conclusion on this, what is the output of /sys/kernel/debug/gpio and gpioinfo (the latter from libgpiod)?

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#20 lore raw

Re: [PATCH v8 3/9] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 83 lines · Andy Shevchenko
Quoted 4 lines · Marek Behún
Quoted 3 lines · Andy Shevchenko
Quoted 2 lines · Marek Behún
Quoted 1 line · Andy Shevchenko

On Tue, Apr 30, 2024 at 2:51 PM Marek Behún <[email protected]> wrote:

...

Quoted 66 lines
Quoted 47 lines
Quoted 47 lines
Quoted 46 lines
Quoted 32 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +32 -0
+static const char * const omnia_mcu_gpio_templates[64] = {
+       /* GPIOs with value read from the 16-bit wide status */
+       [4]  = "gpio%u.MiniPCIe0 Card Detect",
+       [5]  = "gpio%u.MiniPCIe0 mSATA Indicator",
+       [6]  = "gpio%u.Front USB3 port over-current",
+       [7]  = "gpio%u.Rear USB3 port over-current",
+       [8]  = "gpio%u.Front USB3 port power",
+       [9]  = "gpio%u.Rear USB3 port power",
+       [12] = "gpio%u.Front Button",
+
+       /* GPIOs with value read from the 32-bit wide extended status */
+       [16] = "gpio%u.SFP nDET",
+       [28] = "gpio%u.MiniPCIe0 LED",
+       [29] = "gpio%u.MiniPCIe1 LED",
+       [30] = "gpio%u.MiniPCIe2 LED",
+       [31] = "gpio%u.MiniPCIe0 PAN LED",
+       [32] = "gpio%u.MiniPCIe1 PAN LED",
+       [33] = "gpio%u.MiniPCIe2 PAN LED",
+       [34] = "gpio%u.WAN PHY LED0",
+       [35] = "gpio%u.WAN PHY LED1",
+       [36] = "gpio%u.LAN switch p0 LED0",
+       [37] = "gpio%u.LAN switch p0 LED1",
+       [38] = "gpio%u.LAN switch p1 LED0",
+       [39] = "gpio%u.LAN switch p1 LED1",
+       [40] = "gpio%u.LAN switch p2 LED0",
+       [41] = "gpio%u.LAN switch p2 LED1",
+       [42] = "gpio%u.LAN switch p3 LED0",
+       [43] = "gpio%u.LAN switch p3 LED1",
+       [44] = "gpio%u.LAN switch p4 LED0",
+       [45] = "gpio%u.LAN switch p4 LED1",
+       [46] = "gpio%u.LAN switch p5 LED0",
+       [47] = "gpio%u.LAN switch p5 LED1",

drivers/platform/cznic/turris-omnia-mcu-gpio.c line 71

Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10 -0
+
+       /* GPIOs with value read from the 16-bit wide extended control status */
+       [48] = "gpio%u.eMMC nRESET",
+       [49] = "gpio%u.LAN switch nRESET",
+       [50] = "gpio%u.WAN PHY nRESET",
+       [51] = "gpio%u.MiniPCIe0 nPERST",
+       [52] = "gpio%u.MiniPCIe1 nPERST",
+       [53] = "gpio%u.MiniPCIe2 nPERST",
+       [54] = "gpio%u.WAN PHY SFP mux",
+};

You may reduce the memory footprint of these just by doing "gpio%u." part(s) outside. Here compiler won't compress this (as in the case of repetitive string literals),

Quoted 8 lines
Quoted 2 lines

Are you saying that I should dynamically create another array just to pass it to the gpiochip's names pointer?

I have looked into this again and now I'm puzzled how you tested this. To me it seems that those gpio%u will go as a fixed string to the user space, there is no %u --> number substitution happens. Moreover, this data anyway is redundant. Userspace and debugfs all have line numbers being printed.

It gets substituted in drivers/gpio/gpiolib-sysfs.c, function gpiod_export():

dev = device_create_with_groups(&gpio_class, &gdev->dev,

                                  MKDEV(0, 0), data, gpio_groups,
                                  ioname ? ioname : "gpio%u",
                                  desc_to_gpio(desc));

The ioname variable contains the string.

Quoted 8 lines

This is then visible in sysfs:

  $ cd /sys/class/gpio
  $ echo 560 >export
  $ ls
  ...
  gpio560.eMMC nRESET
  ...
Quoted 3 lines

Interesting. But before giving my conclusion on this, what is the output of /sys/kernel/debug/gpio and gpioinfo (the latter from libgpiod)?

It prints %u, as you suspected and I see you already posted patch to avoid this. I'm dropping the "gpio%u." prefixes from GPIO line names.

Marek

author maintainer
#21 lore raw

Re: [PATCH v8 3/9] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

In reply to Andy Shevchenko

On Fri, May 03, 2024 at 07:05:34AM +0300, Andy Shevchenko wrote:
...

Quoted 4 lines
Quoted 1 line

+ err = omnia_cmd_read(client, cmd, &reply, (__fls(bits) >> 3) + 1);

Perhaps a helper for this (__fls(x) >> 3 + (y)) ? It seems it's used in a few places.

It is used 3 times:
rlen = ((__fls(rising) >> 3) << 1) + 1;
flen = ((__fls(falling) >> 3) << 1) + 2;
err = omnia_cmd_read(client, cmd, &reply, (__fls(bits) >> 3) + 1);

The last one is not compatible with the first two (because of the "<< 1").

The first two instances are contained within a function that is dedicated to "computing needed reply length".

I could probably do something like

  static inline unsigned int
  omnia_compute_reply_len(uin32_t mask, bool interleaved, unsigned int offset)
  {
          return ((__fls(mask) >> 3) << interleaved) + 1 + offset;
  }

Then the 3 instances would become

  rlen = omnia_compute_reply_len(rising, true, 0);
  flen = omnia_compute_reply_len(falling, true, 1);
  err = omnia_cmd_read(client, cmd, &reply,
                       omnia_compute_reply_len(bits, false, 0));

What do you think?

#22 lore raw

Re: [PATCH v8 3/9] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 1 line · Marek Behún

On Fri, May 03, 2024 at 07:05:34AM +0300, Andy Shevchenko wrote:

...

Quoted 23 lines
Quoted 4 lines
Quoted 1 line

+ err = omnia_cmd_read(client, cmd, &reply, (__fls(bits) >> 3) + 1);

Perhaps a helper for this (__fls(x) >> 3 + (y)) ? It seems it's used in a few places.

It is used 3 times:
rlen = ((__fls(rising) >> 3) << 1) + 1;
flen = ((__fls(falling) >> 3) << 1) + 2;
err = omnia_cmd_read(client, cmd, &reply, (__fls(bits) >> 3) + 1);

The last one is not compatible with the first two (because of the "<< 1").

The first two instances are contained within a function that is dedicated to "computing needed reply length".

I could probably do something like

  static inline unsigned int
  omnia_compute_reply_len(uin32_t mask, bool interleaved, unsigned int offset)
  {
          return ((__fls(mask) >> 3) << interleaved) + 1 + offset;
  }
Quoted 8 lines

Then the 3 instances would become

  rlen = omnia_compute_reply_len(rising, true, 0);
  flen = omnia_compute_reply_len(falling, true, 1);
  err = omnia_cmd_read(client, cmd, &reply,
                       omnia_compute_reply_len(bits, false, 0));

What do you think?

Fine, but think about these bit operations, I believe it can be optimised.

Signature · 2 lines
With Best Regards,
Andy Shevchenko
author maintainer
#23 lore raw

Re: [PATCH v8 3/9] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Quoted 30 lines · Andy Shevchenko
Quoted 1 line · Marek Behún

On Fri, May 03, 2024 at 07:05:34AM +0300, Andy Shevchenko wrote:

...

Quoted 25 lines
Quoted 4 lines
Quoted 1 line

+ err = omnia_cmd_read(client, cmd, &reply, (__fls(bits) >> 3) + 1);

Perhaps a helper for this (__fls(x) >> 3 + (y)) ? It seems it's used in a few places.

It is used 3 times:
rlen = ((__fls(rising) >> 3) << 1) + 1;
flen = ((__fls(falling) >> 3) << 1) + 2;
err = omnia_cmd_read(client, cmd, &reply, (__fls(bits) >> 3) + 1);

The last one is not compatible with the first two (because of the "<< 1").

The first two instances are contained within a function that is dedicated to "computing needed reply length".

I could probably do something like

  static inline unsigned int
  omnia_compute_reply_len(uin32_t mask, bool interleaved, unsigned int offset)
  {
          return ((__fls(mask) >> 3) << interleaved) + 1 + offset;
  }

Then the 3 instances would become

Quoted 8 lines
Quoted 6 lines
  rlen = omnia_compute_reply_len(rising, true, 0);
  flen = omnia_compute_reply_len(falling, true, 1);
  err = omnia_cmd_read(client, cmd, &reply,
                       omnia_compute_reply_len(bits, false, 0));

What do you think?

Fine, but think about these bit operations, I believe it can be optimised.

I will try something, altough I fear it might need 64-bit operations, which may be even more suboptimal since the driver is supposed to run on armv7.

Also, isn't this premature optimization? Since the computed length is then passed as a parameter to I2C reading, and the I2C bus is orders of magnitudes slower and the handling of I2C requests in Marvell I2C driver will kill any optimization I do here...

author maintainer
#24 lore raw

PATCH v8 4/9 platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup

In reply to Marek Behún

Add support for true board poweroff (MCU can disable all unnecessary voltage regulators) and wakeup at a specified time, implemented via a RTC driver so that the rtcwake utility can be used to configure it.

---
 .../sysfs-bus-i2c-devices-turris-omnia-mcu    |  16 ++
 drivers/platform/cznic/Kconfig                |   4 +
 drivers/platform/cznic/Makefile               |   1 +
 .../platform/cznic/turris-omnia-mcu-base.c    |   5 +
 .../cznic/turris-omnia-mcu-sys-off-wakeup.c   | 258 ++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |  20 ++
 6 files changed, 304 insertions(+)
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu +16 -0
index b27b60d00c87..564119849388 100644
@@ -38,6 +38,22 @@ Description:	(RW) The front button on the Turris Omnia router can be
 
 		Format: %s.
 
+What:		/sys/bus/i2c/devices/<mcu_device>/front_button_poweron
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RW) Newer versions of the microcontroller firmware of the
+		Turris Omnia router support powering off the router into true
+		low power mode. The router can be powered on by pressing the
+		front button.
+
+		This file configures whether front button power on is enabled.
+
+		This file is present only if the power off feature is supported
+		by the firmware.
+
+		Format: %i.
+
 What:		/sys/bus/i2c/devices/<mcu_device>/fw_features
 Date:		July 2024
 KernelVersion:	6.10
drivers/platform/cznic/Kconfig +4 -0
index 3a8c3edcd7e6..0a752aa654fa 100644
@@ -19,10 +19,14 @@ config TURRIS_OMNIA_MCU
 	depends on I2C
 	select GPIOLIB
 	select GPIOLIB_IRQCHIP
+	select RTC_CLASS
 	help
 	  Say Y here to add support for the features implemented by the
 	  microcontroller on the CZ.NIC's Turris Omnia SOHO router.
 	  The features include:
+	  - board poweroff into true low power mode (with voltage regulators
+	    disabled) and the ability to configure wake up from this mode (via
+	    rtcwake)
 	  - 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
drivers/platform/cznic/Makefile +1 -0
index 53fd8f1777a3..a185ef882e44 100644
@@ -3,3 +3,4 @@
 obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
 turris-omnia-mcu-y		:= turris-omnia-mcu-base.o
 turris-omnia-mcu-y		+= turris-omnia-mcu-gpio.o
+turris-omnia-mcu-y		+= turris-omnia-mcu-sys-off-wakeup.o
drivers/platform/cznic/turris-omnia-mcu-base.c +5 -0
index 708b084cb5da..697ace090bda 100644
@@ -195,6 +195,7 @@ static const struct attribute_group omnia_mcu_base_group = {
 static const struct attribute_group *omnia_mcu_groups[] = {
 	&omnia_mcu_base_group,
 	&omnia_mcu_gpio_group,
+	&omnia_mcu_poweroff_group,
 	NULL
 };
 
@@ -360,6 +361,10 @@ static int omnia_mcu_probe(struct i2c_client *client)
 					     "Cannot read board info\n");
 	}
 
+	err = omnia_mcu_register_sys_off_and_wakeup(mcu);
+	if (err)
+		return err;
+
 	return omnia_mcu_register_gpiochip(mcu);
 }
 
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +258 -0

258 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +20 -0
index e8d9bf1c8fdc..6179a4f2069e 100644
@@ -12,9 +12,11 @@
 #include <linux/gpio/driver.h>
 #include <linux/if_ether.h>
 #include <linux/mutex.h>
+#include <linux/rtc.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 struct omnia_mcu {
 	struct i2c_client *client;
@@ -34,6 +36,11 @@ struct omnia_mcu {
 	struct delayed_work button_release_emul_work;
 	u16 last_status;
 	bool button_pressed_emul;
+
+	/* RTC device for configuring wake-up */
+	struct rtc_device *rtcdev;
+	u32 rtc_alarm;
+	bool front_button_poweron;
 };
 
 int omnia_cmd_write_read(const struct i2c_client *client,
@@ -46,6 +53,17 @@ static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
 	return omnia_cmd_write_read(client, cmd, len, NULL, 0);
 }
 
+static inline int omnia_cmd_write_u32(const struct i2c_client *client, u8 cmd,
+				      u32 val)
+{
+	u8 buf[5];
+
+	buf[0] = cmd;
+	put_unaligned_le32(val, &buf[1]);
+
+	return omnia_cmd_write(client, buf, sizeof(buf));
+}
+
 static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
 				 void *reply, unsigned int len)
 {
@@ -107,7 +125,9 @@ static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
 }
 
 extern const struct attribute_group omnia_mcu_gpio_group;
+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);
 
 #endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.43.2
author maintainer
#25 lore raw

PATCH v8 5/9 platform: cznic: turris-omnia-mcu: Add support for MCU watchdog

In reply to Marek Behún

Add support for the watchdog mechanism provided by the MCU.

---
 drivers/platform/cznic/Kconfig                |   2 +
 drivers/platform/cznic/Makefile               |   1 +
 .../platform/cznic/turris-omnia-mcu-base.c    |   4 +
 .../cznic/turris-omnia-mcu-watchdog.c         | 123 ++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |  24 ++++
 5 files changed, 154 insertions(+)
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-watchdog.c
drivers/platform/cznic/Kconfig +2 -0
index 0a752aa654fa..e2649cdecc38 100644
@@ -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
drivers/platform/cznic/Makefile +1 -0
index a185ef882e44..687f7718c0a1 100644
@@ -4,3 +4,4 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
 turris-omnia-mcu-y		:= turris-omnia-mcu-base.o
 turris-omnia-mcu-y		+= turris-omnia-mcu-gpio.o
 turris-omnia-mcu-y		+= turris-omnia-mcu-sys-off-wakeup.o
+turris-omnia-mcu-y		+= turris-omnia-mcu-watchdog.o
drivers/platform/cznic/turris-omnia-mcu-base.c +4 -0
index 697ace090bda..5f88119d825c 100644
@@ -365,6 +365,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);
 }
 
drivers/platform/cznic/turris-omnia-mcu-watchdog.c new file +123 -0

123 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +24 -0
index 6179a4f2069e..1838cb3d636e 100644
@@ -14,6 +14,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>
@@ -41,6 +42,9 @@ struct omnia_mcu {
 	struct rtc_device *rtcdev;
 	u32 rtc_alarm;
 	bool front_button_poweron;
+
+	/* MCU watchdog */
+	struct watchdog_device wdt;
 };
 
 int omnia_cmd_write_read(const struct i2c_client *client,
@@ -53,6 +57,25 @@ static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
 	return omnia_cmd_write_read(client, cmd, len, NULL, 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)
 {
@@ -129,5 +152,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 */
Signature · 1 line
2.43.2
author maintainer
#26 lore raw

PATCH v8 6/9 platform: cznic: turris-omnia-mcu: Add support for MCU provided TRNG

In reply to Marek Behún

Add support for true random number generator provided by the MCU. New Omnia boards come without the Atmel SHA204-A chip. Instead the crypto functionality is provided by new microcontroller, which has a TRNG peripheral.

---
 drivers/platform/cznic/Kconfig                |   2 +
 drivers/platform/cznic/Makefile               |   1 +
 .../platform/cznic/turris-omnia-mcu-base.c    |   6 +-
 .../platform/cznic/turris-omnia-mcu-gpio.c    |   2 +-
 .../platform/cznic/turris-omnia-mcu-trng.c    | 101 ++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |   8 ++
 6 files changed, 118 insertions(+), 2 deletions(-)
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-trng.c
drivers/platform/cznic/Kconfig +2 -0
index e2649cdecc38..750d5f47dba8 100644
@@ -19,6 +19,7 @@ config TURRIS_OMNIA_MCU
 	depends on I2C
 	select GPIOLIB
 	select GPIOLIB_IRQCHIP
+	select HW_RANDOM
 	select RTC_CLASS
 	select WATCHDOG_CORE
 	help
@@ -28,6 +29,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)
+	  - true random number generator (if available on the MCU)
 	  - MCU watchdog
 	  - GPIO pins
 	    - to get front button press events (the front button can be
drivers/platform/cznic/Makefile +1 -0
index 687f7718c0a1..eae4c6b341ff 100644
@@ -4,4 +4,5 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU)	+= turris-omnia-mcu.o
 turris-omnia-mcu-y		:= turris-omnia-mcu-base.o
 turris-omnia-mcu-y		+= turris-omnia-mcu-gpio.o
 turris-omnia-mcu-y		+= turris-omnia-mcu-sys-off-wakeup.o
+turris-omnia-mcu-y		+= turris-omnia-mcu-trng.o
 turris-omnia-mcu-y		+= turris-omnia-mcu-watchdog.o
drivers/platform/cznic/turris-omnia-mcu-base.c +5 -1
index 5f88119d825c..7fe4a3df93a6 100644
@@ -369,7 +369,11 @@ static int omnia_mcu_probe(struct i2c_client *client)
 	if (err)
 		return err;
 
-	return omnia_mcu_register_gpiochip(mcu);
+	err = omnia_mcu_register_gpiochip(mcu);
+	if (err)
+		return err;
+
+	return omnia_mcu_register_trng(mcu);
 }
 
 static const struct of_device_id of_omnia_mcu_match[] = {
drivers/platform/cznic/turris-omnia-mcu-gpio.c +1 -1
index bcc12bd1453c..af20f8076857 100644
@@ -163,7 +163,7 @@ static const struct omnia_gpio {
 };
 
 /* mapping from interrupts to indexes of GPIOs in the omnia_gpios array */
-static const u8 omnia_int_to_gpio_idx[32] = {
+const u8 omnia_int_to_gpio_idx[32] = {
 	[__bf_shf(INT_CARD_DET)]		= 4,
 	[__bf_shf(INT_MSATA_IND)]		= 5,
 	[__bf_shf(INT_USB30_OVC)]		= 6,
drivers/platform/cznic/turris-omnia-mcu-trng.c new file +101 -0

101 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +8 -0
index 1838cb3d636e..e0cf10f8c32e 100644
@@ -9,7 +9,9 @@
 #define __TURRIS_OMNIA_MCU_H
 
 #include <linux/bitops.h>
+#include <linux/completion.h>
 #include <linux/gpio/driver.h>
+#include <linux/hw_random.h>
 #include <linux/if_ether.h>
 #include <linux/mutex.h>
 #include <linux/rtc.h>
@@ -45,6 +47,10 @@ struct omnia_mcu {
 
 	/* MCU watchdog */
 	struct watchdog_device wdt;
+
+	/* true random number generator */
+	struct hwrng trng;
+	struct completion trng_completion;
 };
 
 int omnia_cmd_write_read(const struct i2c_client *client,
@@ -147,11 +153,13 @@ static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd)
 	return err ?: reply;
 }
 
+extern const u8 omnia_int_to_gpio_idx[32];
 extern const struct attribute_group omnia_mcu_gpio_group;
 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_trng(struct omnia_mcu *mcu);
 int omnia_mcu_register_watchdog(struct omnia_mcu *mcu);
 
 #endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.43.2
author maintainer
#27 lore raw

PATCH v8 7/9 platform: cznic: turris-omnia-mcu: Add support for digital message signing via debugfs

In reply to Marek Behún

Add support for digital message signing with private key stored in the MCU. Boards with MKL MCUs have a NIST256p ECDSA private key created when manufactured. The private key is not readable from the MCU, but MCU allows for signing messages with it and retrieving the public key.

As described in a similar commit 50524d787de3 ("firmware:
turris-mox-rwtm: support ECDSA signatures via debugfs"):
The optimal solution would be to register an akcipher provider via kernel's crypto API, but crypto API does not yet support accessing akcipher API from userspace (and probably won't for some time, see
https://www.spinics.net/lists/linux-crypto/msg38388.html).

Therefore we add support for accessing this signature generation mechanism via debugfs for now, so that userspace can access it.

---
 .../ABI/testing/debugfs-turris-omnia-mcu      |  13 ++
 .../sysfs-bus-i2c-devices-turris-omnia-mcu    |  13 ++
 MAINTAINERS                                   |   1 +
 drivers/platform/cznic/Kconfig                |   2 +
 drivers/platform/cznic/Makefile               |   1 +
 .../platform/cznic/turris-omnia-mcu-base.c    |  45 +++-
 .../platform/cznic/turris-omnia-mcu-debugfs.c | 207 ++++++++++++++++++
 drivers/platform/cznic/turris-omnia-mcu.h     |  23 ++
 8 files changed, 304 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/debugfs-turris-omnia-mcu
 create mode 100644 drivers/platform/cznic/turris-omnia-mcu-debugfs.c
Documentation/ABI/testing/debugfs-turris-omnia-mcu new file +13 -0
new file mode 100644
index 000000000000..1665005c2dcd
@@ -0,0 +1,13 @@
+What:		/sys/kernel/debug/turris-omnia-mcu/do_sign
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:
+
+		======= ===========================================================
+		(Write) Message to sign with the ECDSA private key stored in MCU.
+		        The message must be exactly 32 bytes long (since this is
+		        intended to be a SHA-256 hash).
+		(Read)  The resulting signature, 64 bytes. This contains the R and
+			S values of the ECDSA signature, both in big-endian format.
+		======= ===========================================================
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu +13 -0
index 564119849388..b239224cf9bc 100644
@@ -90,6 +90,19 @@ Description:	(RO) Contains the microcontroller type (STM32, GD32, MKL).
 
 		Format: %s.
 
+What:		/sys/bus/i2c/devices/<mcu_device>/public_key
+Date:		July 2024
+KernelVersion:	6.10
+Contact:	Marek Behún <[email protected]>
+Description:	(RO) Contains board ECDSA public key.
+
+		Only available if MCU supports signing messages with the ECDSA
+		algorithm. If so, the board has a private key stored in the MCU
+		that was generated during manufacture and cannot be retrieved
+		from the MCU.
+
+		Format: %s.
+
 What:		/sys/bus/i2c/devices/<mcu_device>/reset_selector
 Date:		July 2024
 KernelVersion:	6.10
MAINTAINERS +1 -0
index 2aa178a9d53e..ecc5aed0a968 100644
@@ -2139,6 +2139,7 @@ M:	Marek Behún <[email protected]>
 S:	Maintained
 W:	https://www.turris.cz/
 F:	Documentation/ABI/testing/debugfs-moxtet
+F:	Documentation/ABI/testing/debugfs-turris-omnia-mcu
 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
drivers/platform/cznic/Kconfig +2 -0
index 750d5f47dba8..2d45495c0a2d 100644
@@ -30,6 +30,8 @@ config TURRIS_OMNIA_MCU
 	    disabled) and the ability to configure wake up from this mode (via
 	    rtcwake)
 	  - true random number generator (if available on the MCU)
+	  - ECDSA message signing with board private key (if available on the
+	    MCU)
 	  - MCU watchdog
 	  - GPIO pins
 	    - to get front button press events (the front button can be
drivers/platform/cznic/Makefile +1 -0
index eae4c6b341ff..af9213928404 100644
@@ -6,3 +6,4 @@ turris-omnia-mcu-y		+= turris-omnia-mcu-gpio.o
 turris-omnia-mcu-y		+= turris-omnia-mcu-sys-off-wakeup.o
 turris-omnia-mcu-y		+= turris-omnia-mcu-trng.o
 turris-omnia-mcu-y		+= turris-omnia-mcu-watchdog.o
+turris-omnia-mcu-$(CONFIG_DEBUG_FS) += turris-omnia-mcu-debugfs.o
drivers/platform/cznic/turris-omnia-mcu-base.c +44 -1

81 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu-debugfs.c new file +207 -0

207 lines not on this page · raw message

drivers/platform/cznic/turris-omnia-mcu.h +23 -0
index e0cf10f8c32e..5ce639d5ec67 100644
@@ -21,6 +21,9 @@
 #include <asm/byteorder.h>
 #include <asm/unaligned.h>
 
+#define OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN	33
+#define OMNIA_MCU_CRYPTO_SIGNATURE_LEN	64
+
 struct omnia_mcu {
 	struct i2c_client *client;
 	const char *type;
@@ -30,6 +33,7 @@ struct omnia_mcu {
 	u64 board_serial_number;
 	u8 board_first_mac[ETH_ALEN];
 	u8 board_revision;
+	u8 board_public_key[OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN];
 
 	/* GPIO chip */
 	struct gpio_chip gc;
@@ -51,6 +55,16 @@ struct omnia_mcu {
 	/* true random number generator */
 	struct hwrng trng;
 	struct completion trng_completion;
+
+#ifdef CONFIG_DEBUG_FS
+	/* MCU ECDSA message signing via debugfs */
+	struct dentry *debugfs_root;
+	struct completion msg_signed_completion;
+	struct mutex sign_lock;
+	unsigned int sign_state;
+	u8 signature[OMNIA_MCU_CRYPTO_SIGNATURE_LEN];
+	int sign_err;
+#endif
 };
 
 int omnia_cmd_write_read(const struct i2c_client *client,
@@ -162,4 +176,13 @@ int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu);
 int omnia_mcu_register_trng(struct omnia_mcu *mcu);
 int omnia_mcu_register_watchdog(struct omnia_mcu *mcu);
 
+#ifdef CONFIG_DEBUG_FS
+int omnia_mcu_register_debugfs(struct omnia_mcu *mcu);
+#else
+static inline int omnia_mcu_register_debugfs(struct omnia_mcu *mcu)
+{
+	return 0;
+}
+#endif
+
 #endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.43.2
author maintainer
#28 lore raw

PATCH v8 8/9 ARM: dts: turris-omnia: Add MCU system-controller node

In reply to Marek Behún

Turris Omnia's MCU provides various features that can be configured over I2C at address 0x2a. Add device-tree node.

This does not carry a Fixes tag - we do not want this to get backported to stable kernels for the following reason: U-Boot since v2022.10 inserts a phy-reset-gpio property into the WAN ethernet node pointing to the MCU node if it finds the MCU node with a cznic,turris-omnia-mcu compatible. Thus if this change got backported to a stable kernel, the WAN interface driver would defer probe indefinitely (since it would wait for the turris-omnia-mcu driver which would not be present).

---
 .../dts/marvell/armada-385-turris-omnia.dts   | 22 ++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)
arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts +21 -1
index 7b755bb4e4e7..59079d63fe27 100644
@@ -218,7 +218,22 @@ i2c@0 {
 			#size-cells = <0>;
 			reg = <0>;
 
-			/* STM32F0 command interface at address 0x2a */
+			mcu: system-controller@2a {
+				compatible = "cznic,turris-omnia-mcu";
+				reg = <0x2a>;
+
+				pinctrl-names = "default";
+				pinctrl-0 = <&mcu_pins>;
+
+				interrupt-parent = <&gpio1>;
+				interrupts = <11 IRQ_TYPE_NONE>;
+
+				gpio-controller;
+				#gpio-cells = <3>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+			};
 
 			led-controller@2b {
 				compatible = "cznic,turris-omnia-leds";
@@ -501,6 +516,11 @@ fixed-link {
 };
 
 &pinctrl {
+	mcu_pins: mcu-pins {
+		marvell,pins = "mpp43";
+		marvell,function = "gpio";
+	};
+
 	pcawan_pins: pcawan-pins {
 		marvell,pins = "mpp46";
 		marvell,function = "gpio";
Signature · 1 line
2.43.2
author maintainer
#29 lore raw

PATCH v8 9/9 ARM: dts: turris-omnia: Add GPIO key node for front button

In reply to Marek Behún

Now that we have the MCU device-tree node, which acts as a GPIO controller, add GPIO key node for the front button.

---
 .../boot/dts/marvell/armada-385-turris-omnia.dts    | 13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts +13 -0
index 59079d63fe27..43202890c959 100644
@@ -112,6 +112,19 @@ sfp: sfp {
 		status = "disabled";
 	};
 
+	gpio-keys {
+		compatible = "gpio-keys";
+
+		front-button {
+			label = "Front Button";
+			linux,code = <KEY_VENDOR>;
+			linux,can-disable;
+			gpios = <&mcu 0 12 GPIO_ACTIVE_HIGH>;
+			/* debouncing is done by the microcontroller */
+			debounce-interval = <0>;
+		};
+	};
+
 	sound {
 		compatible = "simple-audio-card";
 		simple-audio-card,name = "SPDIF";
Signature · 1 line
2.43.2