]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
clk: add clock driver for SCMI agents
authorEtienne Carriere <etienne.carriere@linaro.org>
Wed, 9 Sep 2020 16:44:04 +0000 (18:44 +0200)
committerTom Rini <trini@konsulko.com>
Wed, 30 Sep 2020 15:55:23 +0000 (11:55 -0400)
This change introduces a clock driver for SCMI agent devices. When
SCMI agent and SCMI clock drivers are enabled, SCMI agent binds a
clock device for each SCMI clock protocol devices enabled in the FDT.

SCMI clock driver is embedded upon CONFIG_CLK_SCMI=y. If enabled,
CONFIG_SCMI_AGENT is also enabled.

SCMI Clock protocol is defined in the SCMI specification [1].

Links: [1] https://developer.arm.com/architectures/system-architectures/software-standards/scmi
Signed-off-by: Etienne Carriere <etienne.carriere@linaro.org>
Cc: Lukasz Majewski <lukma@denx.de>
Cc: Simon Glass <sjg@chromium.org>
Cc: Peng Fan <peng.fan@nxp.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/clk_scmi.c [new file with mode: 0644]
drivers/firmware/scmi/scmi_agent-uclass.c
include/scmi_protocols.h

index 6003e140b58228207d6ce833542b0f204e6975af..4dfbad7986b11f6dd2a296ba46f4e0574d64547d 100644 (file)
@@ -159,6 +159,14 @@ config CLK_CDCE9XX
           Enable the clock synthesizer driver for CDCE913/925/937/949
           series of chips.
 
+config CLK_SCMI
+       bool "Enable SCMI clock driver"
+       depends on SCMI_FIRMWARE
+       help
+         Enable this option if you want to support clock devices exposed
+         by a SCMI agent based on SCMI clock protocol communication
+         with a SCMI server.
+
 source "drivers/clk/analogbits/Kconfig"
 source "drivers/clk/at91/Kconfig"
 source "drivers/clk/exynos/Kconfig"
index cda4b4b605f191ee60e57b902b471671e9d64abe..d1e295ac7c1d4ed3a7ec1c2cd0f2d6bc4e8dc949 100644 (file)
@@ -32,6 +32,7 @@ obj-$(CONFIG_CLK_MPC83XX) += mpc83xx_clk.o
 obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o
 obj-$(CONFIG_CLK_OWL) += owl/
 obj-$(CONFIG_CLK_RENESAS) += renesas/
+obj-$(CONFIG_CLK_SCMI) += clk_scmi.o
 obj-$(CONFIG_CLK_SIFIVE) += sifive/
 obj-$(CONFIG_ARCH_SUNXI) += sunxi/
 obj-$(CONFIG_CLK_STM32F) += clk_stm32f.o
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
new file mode 100644 (file)
index 0000000..93a4819
--- /dev/null
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019-2020 Linaro Limited
+ */
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <asm/types.h>
+
+static int scmi_clk_gate(struct clk *clk, int enable)
+{
+       struct scmi_clk_state_in in = {
+               .clock_id = clk->id,
+               .attributes = enable,
+       };
+       struct scmi_clk_state_out out;
+       struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+                                         SCMI_CLOCK_CONFIG_SET,
+                                         in, out);
+       int ret;
+
+       ret = devm_scmi_process_msg(clk->dev->parent, &msg);
+       if (ret)
+               return ret;
+
+       return scmi_to_linux_errno(out.status);
+}
+
+static int scmi_clk_enable(struct clk *clk)
+{
+       return scmi_clk_gate(clk, 1);
+}
+
+static int scmi_clk_disable(struct clk *clk)
+{
+       return scmi_clk_gate(clk, 0);
+}
+
+static ulong scmi_clk_get_rate(struct clk *clk)
+{
+       struct scmi_clk_rate_get_in in = {
+               .clock_id = clk->id,
+       };
+       struct scmi_clk_rate_get_out out;
+       struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+                                         SCMI_CLOCK_RATE_GET,
+                                         in, out);
+       int ret;
+
+       ret = devm_scmi_process_msg(clk->dev->parent, &msg);
+       if (ret < 0)
+               return ret;
+
+       ret = scmi_to_linux_errno(out.status);
+       if (ret < 0)
+               return ret;
+
+       return (ulong)(((u64)out.rate_msb << 32) | out.rate_lsb);
+}
+
+static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
+{
+       struct scmi_clk_rate_set_in in = {
+               .clock_id = clk->id,
+               .flags = SCMI_CLK_RATE_ROUND_CLOSEST,
+               .rate_lsb = (u32)rate,
+               .rate_msb = (u32)((u64)rate >> 32),
+       };
+       struct scmi_clk_rate_set_out out;
+       struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK,
+                                         SCMI_CLOCK_RATE_SET,
+                                         in, out);
+       int ret;
+
+       ret = devm_scmi_process_msg(clk->dev->parent, &msg);
+       if (ret < 0)
+               return ret;
+
+       ret = scmi_to_linux_errno(out.status);
+       if (ret < 0)
+               return ret;
+
+       return scmi_clk_get_rate(clk);
+}
+
+static const struct clk_ops scmi_clk_ops = {
+       .enable = scmi_clk_enable,
+       .disable = scmi_clk_disable,
+       .get_rate = scmi_clk_get_rate,
+       .set_rate = scmi_clk_set_rate,
+};
+
+U_BOOT_DRIVER(scmi_clock) = {
+       .name = "scmi_clk",
+       .id = UCLASS_CLK,
+       .ops = &scmi_clk_ops,
+};
index 67a6f907c99e0cf0c774b4a2d4af24f0e50af455..1f36f23b6d866859d2b3137331cbb844bb4c136e 100644 (file)
@@ -58,9 +58,9 @@ static int scmi_bind_protocols(struct udevice *dev)
 {
        int ret = 0;
        ofnode node;
-       struct driver *drv;
 
        dev_for_each_subnode(node, dev) {
+               struct driver *drv = NULL;
                u32 protocol_id;
 
                if (!ofnode_is_available(node))
@@ -70,9 +70,17 @@ static int scmi_bind_protocols(struct udevice *dev)
                        continue;
 
                switch (protocol_id) {
+               case SCMI_PROTOCOL_ID_CLOCK:
+                       if (IS_ENABLED(CONFIG_CLK_SCMI))
+                               drv = DM_GET_DRIVER(scmi_clock);
+                       break;
                default:
-                       dev_info(dev, "Ignore unsupported SCMI protocol %#x\n",
-                                protocol_id);
+                       break;
+               }
+
+               if (!drv) {
+                       dev_dbg(dev, "Ignore unsupported SCMI protocol %#x\n",
+                               protocol_id);
                        continue;
                }
 
index 86a2d109c8ccdd74e10ca7902a29f5da05ebf6e0..4778bcfc4744d9446104bfe1e1e66cc523bed162 100644 (file)
@@ -7,6 +7,7 @@
 #define _SCMI_PROTOCOLS_H
 
 #include <linux/bitops.h>
+#include <asm/types.h>
 
 /*
  * Subset the SCMI protocols definition
@@ -38,4 +39,81 @@ enum scmi_status_code {
        SCMI_PROTOCOL_ERROR = -10,
 };
 
+/*
+ * SCMI Clock Protocol
+ */
+
+enum scmi_clock_message_id {
+       SCMI_CLOCK_RATE_SET = 0x5,
+       SCMI_CLOCK_RATE_GET = 0x6,
+       SCMI_CLOCK_CONFIG_SET = 0x7,
+};
+
+#define SCMI_CLK_RATE_ASYNC_NOTIFY     BIT(0)
+#define SCMI_CLK_RATE_ASYNC_NORESP     (BIT(0) | BIT(1))
+#define SCMI_CLK_RATE_ROUND_DOWN       0
+#define SCMI_CLK_RATE_ROUND_UP         BIT(2)
+#define SCMI_CLK_RATE_ROUND_CLOSEST    BIT(3)
+
+/**
+ * struct scmi_clk_state_in - Message payload for CLOCK_CONFIG_SET command
+ * @clock_id:  SCMI clock ID
+ * @attributes:        Attributes of the targets clock state
+ */
+struct scmi_clk_state_in {
+       u32 clock_id;
+       u32 attributes;
+};
+
+/**
+ * struct scmi_clk_state_out - Response payload for CLOCK_CONFIG_SET command
+ * @status:    SCMI command status
+ */
+struct scmi_clk_state_out {
+       s32 status;
+};
+
+/**
+ * struct scmi_clk_state_in - Message payload for CLOCK_RATE_GET command
+ * @clock_id:  SCMI clock ID
+ * @attributes:        Attributes of the targets clock state
+ */
+struct scmi_clk_rate_get_in {
+       u32 clock_id;
+};
+
+/**
+ * struct scmi_clk_rate_get_out - Response payload for CLOCK_RATE_GET command
+ * @status:    SCMI command status
+ * @rate_lsb:  32bit LSB of the clock rate in Hertz
+ * @rate_msb:  32bit MSB of the clock rate in Hertz
+ */
+struct scmi_clk_rate_get_out {
+       s32 status;
+       u32 rate_lsb;
+       u32 rate_msb;
+};
+
+/**
+ * struct scmi_clk_state_in - Message payload for CLOCK_RATE_SET command
+ * @clock_id:  SCMI clock ID
+ * @flags:     Flags for the clock rate set request
+ * @rate_lsb:  32bit LSB of the clock rate in Hertz
+ * @rate_msb:  32bit MSB of the clock rate in Hertz
+ */
+struct scmi_clk_rate_set_in {
+       u32 clock_id;
+       u32 flags;
+       u32 rate_lsb;
+       u32 rate_msb;
+};
+
+/**
+ * struct scmi_clk_rate_set_out - Response payload for CLOCK_RATE_SET command
+ * @status:    SCMI command status
+ */
+struct scmi_clk_rate_set_out {
+       s32 status;
+};
+
 #endif /* _SCMI_PROTOCOLS_H */