>-----Original Message-----
>From: U-Boot <[email protected]> On Behalf Of Mathew McBride
>Sent: Wednesday, November 3, 2021 10:59 AM
>To: [email protected]; Priyanka Jain <[email protected]>
>Cc: Mathew McBride <[email protected]>
>Subject: [PATCH 1/2] board: traverse: add Ten64 board controller driver
>
>Traverse Technologies Ten64 family boards use a microcontroller to control low
>level board functions like startup and reset, as well as holding details such 
>as the
>board MAC address.
>
>Communication between the CPU and microcontroller is via I2C.
>
>To keep the driver structure clean between the Ten64 board file, DM_I2C, and a
>future utility command, this driver has been implemented as a misc uclass 
>device.
>
>Signed-off-by: Mathew McBride <[email protected]>
>---
> board/traverse/common/Kconfig            |   6 +
> board/traverse/common/Makefile           |   1 +
> board/traverse/common/ten64-controller.h |  28 +++
>board/traverse/common/ten64_controller.c | 238 +++++++++++++++++++++++
> 4 files changed, 273 insertions(+)
> create mode 100644 board/traverse/common/Kconfig  create mode 100644
>board/traverse/common/Makefile  create mode 100644
>board/traverse/common/ten64-controller.h
> create mode 100644 board/traverse/common/ten64_controller.c
>
>diff --git a/board/traverse/common/Kconfig b/board/traverse/common/Kconfig
>new file mode 100644 index 0000000000..d34832bd0d
>--- /dev/null
>+++ b/board/traverse/common/Kconfig
>@@ -0,0 +1,6 @@
>+config TEN64_CONTROLLER
>+      bool "Enable Ten64 board controller driver"
>+      depends on TARGET_TEN64
>+      help
>+              Support for the board microcontroller on the Traverse
>+              Ten64 family of boards.
>diff --git a/board/traverse/common/Makefile
>b/board/traverse/common/Makefile new file mode 100644 index
>0000000000..d31e3535b9
>--- /dev/null
>+++ b/board/traverse/common/Makefile
>@@ -0,0 +1 @@
>+obj-$(CONFIG_TEN64_CONTROLLER) += ten64_controller.o
>diff --git a/board/traverse/common/ten64-controller.h
>b/board/traverse/common/ten64-controller.h
>new file mode 100644
>index 0000000000..fed6af470d
>--- /dev/null
>+++ b/board/traverse/common/ten64-controller.h
>@@ -0,0 +1,28 @@
>+/* SPDX-License-Identifier: GPL-2.0+ */ #ifndef TEN64_CNTRL_H #define
>+TEN64_CNTRL_H
>+
>+/**
>+ * struct t64uc_board_info - Board Information Structure
>+ * @mac: Base MAC address
>+ * @cpuId: Microcontroller unique serial number
>+ * @fwversion_major: Microcontroller version number (Major)
>+ * @fwversion_minor: Microcontroller version number (Minor)
>+ * @fwversion_patch: Microcontroller version number (Patch)  */ struct
>+t64uc_board_info {
>+      u8 mac[6];
>+      u32 cpuId[4];
>+      u8 fwversion_major;
>+      u8 fwversion_minor;
>+      u8 fwversion_patch;
>+} __packed;
>+
>+enum {
>+      TEN64_CNTRL_GET_BOARD_INFO,
>+      TEN64_CNTRL_10G_OFF,
>+      TEN64_CNTRL_10G_ON,
>+      TEN64_CNTRL_SET_NEXT_BOOTSRC
>+};
>+
>+#endif
>diff --git a/board/traverse/common/ten64_controller.c
>b/board/traverse/common/ten64_controller.c
>new file mode 100644
>index 0000000000..11e068f94f
>--- /dev/null
>+++ b/board/traverse/common/ten64_controller.c
>@@ -0,0 +1,238 @@
>+// SPDX-License-Identifier: GPL-2.0+
>+
>+/* Ten64 Board Microcontroller Driver
>+ * Copyright 2021 Traverse Technologies Australia
>+ *
>+ */
>+
>+#include <common.h>
>+#include <dm.h>
>+#include <misc.h>
>+#include <i2c.h>
>+#include <hexdump.h>
>+#include <dm/device_compat.h>
>+#include <inttypes.h>
>+#include <linux/delay.h>
>+
>+#include "ten64-controller.h"
>+
>+/* Microcontroller command set and structure
>+ * These should not be used outside this file  */
>+
>+#define T64_UC_DATA_MAX_SIZE            128U
>+#define T64_UC_API_MSG_HEADER_SIZE      4U
>+#define T64_UC_API_HEADER_PREAMB        0xcabe
>+
>+#define TEN64_UC_CMD_SET_BOARD_MAC            0x10
>+#define TEN64_UC_CMD_GET_BOARD_INFO           0x11
>+
>+#define TEN64_UC_CMD_GET_STATE                        0x20
>+#define TEN64_UC_CMD_SET_RESET_BTN_HOLD_TIME  0x21
>+#define TEN64_UC_CMD_ENABLE_RESET_BUTTON      0x22
>+#define TEN64_UC_CMD_SET_NEXT_BOOTSRC         0x23
>+#define TEN64_UC_CMD_ENABLE_10G               0x24
>+
>+#define TEN64_UC_CMD_FWUP_GET_INFO            0xA0
>+#define TEN64_UC_CMD_FWUP_INIT                        0xA1
>+#define TEN64_UC_CMD_FWUP_XFER                        0xA2
>+#define TEN64_UC_CMD_FWUP_CHECK               0xA3
>+#define TEN64_UC_CMD_FWUPBOOT                 0xA
>+
>+/** struct t64uc_message - Wire Format for microcontroller messages
>+ * @preamb: Message preamble (always 0xcabe)
>+ * @cmd: Command to invoke
>+ * @len: Length of data
>+ * @data: Command data, up to 128 bytes  */ struct t64uc_message {
>+      u16 preamb;
>+      u8 cmd;
>+      u8 len;
>+      u8 data[T64_UC_DATA_MAX_SIZE];
>+}  __packed;
>+
>+#define       T64_CTRL_IO_SET         1U
>+#define       T64_CTRL_IO_CLEAR       2U
>+#define       T64_CTRL_IO_TOGGLE      3U
>+#define       T64_CTRL_IO_RESET       4U
>+#define       T64_CTRL_IO_UNKNOWN     5U
>+
>+/** struct t64uc_board_10g_enable - Wrapper for 10G enable command
>+ * @control: state to set the 10G retimer - either
>+ *         T64_CTRL_IO_CLEAR (0x02) for off or
>+ *         T64_CTRL_IO_SET (0x01) for on.
>+ *
>+ * This struct exists to simplify the wrapping of the
>+ * command value into a microcontroller message and passing into
>+ * functions.
>+ */
>+struct t64uc_board_10g_enable {
>+      u8 control;
>+} __packed;
>+
>+/** ten64_controller_send_recv_command() - Wrapper function to
>+ * send a command to the microcontroller.
>+ * @uc_chip: the DM I2C chip handle for the microcontroller
>+ * @uc_cmd: the microcontroller API command code
>+ * @uc_cmd_data: pointer to the data struct for this command
>+ * @uc_data_len: size of command data struct
>+ * @return_data: place to store response from microcontroller, NULL if
>+not expected
>+ * @expected_return_len: expected size of microcontroller command
>+response
>+ * @return_message_wait: wait this long (in us) before reading the
>+response
>+ *
>+ * Invoke a microcontroller command and receive a response.
>+ * This function includes communicating with the microcontroller over
>+ * I2C and encoding a message in the wire format.
>+ *
>+ * Return: 0 if successful, error code otherwise.
>+ * Returns -EBADMSG if the microcontroller response could not be
>+validated,
>+ * other error codes may be passed from dm_i2c_xfer()  */ static int
>+ten64_controller_send_recv_command(struct udevice *ucdev, u8 uc_cmd,
>+                                            void *uc_cmd_data, u8
>cmd_data_len,
>+                                            void *return_data, u8
>expected_return_len,
>+                                            u16 return_message_wait)
>+{
>+      int ret;
>+      struct t64uc_message send, recv;
>+      struct i2c_msg command_message, return_message;
>+      struct dm_i2c_chip *chip = dev_get_parent_plat(ucdev);
>+
>+      dev_dbg(ucdev, "%s sending cmd %02X len %d\n", __func__, uc_cmd,
>+cmd_data_len);
>+
>+      send.preamb = T64_UC_API_HEADER_PREAMB;
>+      send.cmd = uc_cmd;
>+      send.len = cmd_data_len;
>+      if (uc_cmd_data && cmd_data_len > 0)
>+              memcpy(send.data, uc_cmd_data, cmd_data_len);
>+
>+      command_message.addr = chip->chip_addr;
>+      command_message.len = T64_UC_API_MSG_HEADER_SIZE + send.len;
>+      command_message.buf = (void *)&send;
>+      command_message.flags = I2C_M_STOP;
>+
>+      ret = dm_i2c_xfer(ucdev, &command_message, 1);
>+      if (!return_data)
>+              return ret;
>+
>+      udelay(return_message_wait);
>+
>+      return_message.addr = chip->chip_addr;
>+      return_message.len = T64_UC_API_MSG_HEADER_SIZE +
>expected_return_len;
>+      return_message.buf = (void *)&recv;
>+      return_message.flags = I2C_M_RD;
>+
>+      ret = dm_i2c_xfer(ucdev, &return_message, 1);
>+      if (ret)
>+              return ret;
>+
>+      if (recv.preamb != T64_UC_API_HEADER_PREAMB) {
>+              dev_err(ucdev, "%s: No preamble received in microcontroller
>response\n",
>+                      __func__);
>+              return -EBADMSG;
>+      }
>+      if (recv.cmd != uc_cmd) {
>+              dev_err(ucdev, "%s: command response mismatch, got %02X
>expecting %02X\n",
>+                      __func__, recv.cmd, uc_cmd);
>+              return -EBADMSG;
>+      }
>+      if (recv.len != expected_return_len) {
>+              dev_err(ucdev, "%s: received message has unexpected length,
>got %d expected %d\n",
>+                      __func__, recv.len, expected_return_len);
>+              return -EBADMSG;
>+      }
>+      memcpy(return_data, recv.data, expected_return_len);
>+      return ret;
>+}
>+
>+/** ten64_controller_send_command() - Send command to microcontroller
>+without
>+ * expecting a response (for example, invoking a control command)
>+ * @uc_chip: the DM I2C chip handle for the microcontroller
>+ * @uc_cmd: the microcontroller API command code
>+ * @uc_cmd_data: pointer to the data struct for this command
>+ * @uc_data_len: size of command data struct  */ static int
>+ten64_controller_send_command(struct udevice *ucdev, u8 uc_cmd,
>+                                       void *uc_cmd_data, u8 cmd_data_len)
>{
>+      return ten64_controller_send_recv_command(ucdev, uc_cmd,
>+                                                uc_cmd_data, cmd_data_len,
>+                                                NULL, 0, 0);
>+}
>+
>+/** ten64_controller_get_board_info() - Get board information from
>+microcontroller
>+ * @dev: The microcontroller device handle
>+ * @out: Pointer to a t64uc_board_info struct that has been allocated
>+by the caller  */ static int ten64_controller_get_board_info(struct
>+udevice *dev, struct t64uc_board_info *out) {
>+      int ret;
>+
>+      ret = ten64_controller_send_recv_command(dev,
>TEN64_UC_CMD_GET_BOARD_INFO,
>+                                               NULL, 0, out,
>+                                               sizeof(struct 
>t64uc_board_info),
>+                                               10000);
>+      if (ret) {
>+              dev_err(dev, "%s unable to send board info command: %d\n",
>+                      __func__, ret);
>+              return ret;
>+      }
>+
>+      return 0;
>+}
>+
>+/**
>+ * ten64_controller_10g_enable_command() - Sends a 10G (Retimer) enable
>+command
>+ * to the microcontroller.
>+ * @ucdev: The microcontroller udevice
>+ * @value: The value flag for the 10G state  */ static int
>+ten64_controller_10g_enable_command(struct udevice *ucdev, u8 value) {
>+      int ret;
>+      struct t64uc_board_10g_enable enable_msg;
>+
>+      enable_msg.control = value;
>+
>+      ret = ten64_controller_send_command(ucdev,
>TEN64_UC_CMD_ENABLE_10G,
>+                                          &enable_msg, sizeof(enable_msg));
>+      if (ret) {
>+              dev_err(ucdev, "ERROR sending uC 10G Enable message: %d\n",
>ret);
>+              return -1;
>+      }
>+
>+      return 0;
>+}
>+
>+int ten64_controller_call(struct udevice *dev, int msgid, void *tx_msg, int
>tx_size,
>+                        void *rx_msg, int rx_size)
>+{
>+      switch (msgid) {
>+      case TEN64_CNTRL_GET_BOARD_INFO:
>+              return ten64_controller_get_board_info(dev, (struct
>t64uc_board_info *)rx_msg);
>+      case TEN64_CNTRL_10G_OFF:
>+              return ten64_controller_10g_enable_command(dev,
>T64_CTRL_IO_CLEAR);
>+      case TEN64_CNTRL_10G_ON:
>+              return ten64_controller_10g_enable_command(dev,
>T64_CTRL_IO_SET);
>+      default:
>+              dev_err(dev, "%s: Unknown operation %d\n", __func__, msgid);
>+      }
>+      return -EINVAL;
>+}
>+
>+static struct misc_ops ten64_ctrl_ops  = {
>+      .call = ten64_controller_call
>+};
>+
>+static const struct udevice_id ten64_controller_ids[] = {
>+      {.compatible = "traverse,ten64-controller"},
>+      {}
>+};
>+
>+U_BOOT_DRIVER(ten64_controller) = {
>+      .name = "ten64-controller-i2c",
>+      .id = UCLASS_MISC,
>+      .of_match = ten64_controller_ids,
>+      .ops = &ten64_ctrl_ops
>+};
>--
>2.30.1

Many checkpatch warnings and CHECKS in the series. Kindly help to fix.

Regards
Priyanka

Reply via email to