Skip to content

Commit

Permalink
firmware: scmi: add support for clock management protocol
Browse files Browse the repository at this point in the history
This includes:
	1) Source containing helper functions, each
	implementing a command from the clock management
	protocol.

	2) A clock controller driver making use of said
	helper functions and implementing the clock
	subsystem API.

	3) A DT binding for clock protocol node.

Signed-off-by: Laurentiu Mihalcea <[email protected]>
  • Loading branch information
LaurentiuM1234 authored and nashif committed Aug 19, 2024
1 parent 413c77c commit 350e36a
Show file tree
Hide file tree
Showing 9 changed files with 398 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/clock_control/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ zephyr_library()

zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_BEETLE beetle_clock_control.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ADSP clock_control_adsp.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ARM_SCMI clock_control_arm_scmi.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_ESP32 clock_control_esp32.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_FIXED_RATE_CLOCK clock_control_fixed_rate.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_GD32 clock_control_gd32.c)
Expand Down
2 changes: 2 additions & 0 deletions drivers/clock_control/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,6 @@ source "drivers/clock_control/Kconfig.rpi_pico"

source "drivers/clock_control/Kconfig.nrf_auxpll"

source "drivers/clock_control/Kconfig.arm_scmi"

endif # CLOCK_CONTROL
8 changes: 8 additions & 0 deletions drivers/clock_control/Kconfig.arm_scmi
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright 2024 NXP

config CLOCK_CONTROL_ARM_SCMI
bool "SCMI clock protocol clock controller driver"
default y
depends on ARM_SCMI_CLK_HELPERS
help
Enable support for SCMI-based clock control.
102 changes: 102 additions & 0 deletions drivers/clock_control/clock_control_arm_scmi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/drivers/firmware/scmi/clk.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(arm_scmi_clock);

#define DT_DRV_COMPAT arm_scmi_clock

struct scmi_clock_data {
uint32_t clk_num;
};

static int scmi_clock_on_off(const struct device *dev,
clock_control_subsys_t clk, bool on)
{
struct scmi_clock_data *data;
struct scmi_protocol *proto;
uint32_t clk_id;
struct scmi_clock_config cfg;

proto = dev->data;
data = proto->data;
clk_id = POINTER_TO_UINT(clk);

if (clk_id >= data->clk_num) {
return -EINVAL;
}

memset(&cfg, 0, sizeof(cfg));

cfg.attributes = SCMI_CLK_CONFIG_ENABLE_DISABLE(on);
cfg.clk_id = clk_id;

return scmi_clock_config_set(proto, &cfg);
}

static int scmi_clock_on(const struct device *dev, clock_control_subsys_t clk)
{
return scmi_clock_on_off(dev, clk, true);
}

static int scmi_clock_off(const struct device *dev, clock_control_subsys_t clk)
{
return scmi_clock_on_off(dev, clk, false);
}

static int scmi_clock_get_rate(const struct device *dev,
clock_control_subsys_t clk, uint32_t *rate)
{
struct scmi_clock_data *data;
struct scmi_protocol *proto;
uint32_t clk_id;

proto = dev->data;
data = proto->data;
clk_id = POINTER_TO_UINT(clk);

if (clk_id >= data->clk_num) {
return -EINVAL;
}

return scmi_clock_rate_get(proto, clk_id, rate);
}

static struct clock_control_driver_api scmi_clock_api = {
.on = scmi_clock_on,
.off = scmi_clock_off,
.get_rate = scmi_clock_get_rate,
};

static int scmi_clock_init(const struct device *dev)
{
struct scmi_protocol *proto;
struct scmi_clock_data *data;
int ret;
uint32_t attributes;

proto = dev->data;
data = proto->data;

ret = scmi_clock_protocol_attributes(proto, &attributes);
if (ret < 0) {
LOG_ERR("failed to fetch clock attributes: %d", ret);
return ret;
}

data->clk_num = SCMI_CLK_ATTRIBUTES_CLK_NUM(attributes);

return 0;
}

static struct scmi_clock_data data;

DT_INST_SCMI_PROTOCOL_DEFINE(0, &scmi_clock_init, NULL, &data, NULL,
PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
&scmi_clock_api);
3 changes: 3 additions & 0 deletions drivers/firmware/scmi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ zephyr_library()
zephyr_library_sources_ifdef(CONFIG_ARM_SCMI core.c)
zephyr_library_sources_ifdef(CONFIG_ARM_SCMI_MAILBOX_TRANSPORT mailbox.c)
zephyr_library_sources_ifdef(CONFIG_ARM_SCMI_SHMEM shmem.c)

# SCMI protocol helper files
zephyr_library_sources_ifdef(CONFIG_ARM_SCMI_CLK_HELPERS clk.c)
7 changes: 7 additions & 0 deletions drivers/firmware/scmi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@

if ARM_SCMI

config ARM_SCMI_CLK_HELPERS
bool "Helper functions for SCMI clock protocol"
default y
depends on DT_HAS_ARM_SCMI_CLOCK_ENABLED
help
Enable support for SCMI clock protocol helper functions.

config ARM_SCMI_MAILBOX_TRANSPORT
bool "SCMI transport based on shared memory and doorbells"
default y
Expand Down
152 changes: 152 additions & 0 deletions drivers/firmware/scmi/clk.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/drivers/firmware/scmi/clk.h>
#include <string.h>

/* TODO: if extended attributes are supported this should be moved
* to the header file so that users will have access to it.
*/
#define SCMI_CLK_CONFIG_EA_MASK GENMASK(23, 16)

struct scmi_clock_attributes_reply {
int32_t status;
uint32_t attributes;
};

struct scmi_clock_rate_set_reply {
int32_t status;
uint32_t rate[2];
};

int scmi_clock_rate_get(struct scmi_protocol *proto,
uint32_t clk_id, uint32_t *rate)
{
struct scmi_message msg, reply;
int ret;
struct scmi_clock_rate_set_reply reply_buffer;

/* sanity checks */
if (!proto || !rate) {
return -EINVAL;
}

if (proto->id != SCMI_PROTOCOL_CLOCK) {
return -EINVAL;
}

msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_CLOCK_RATE_GET,
SCMI_COMMAND, proto->id, 0x0);
msg.len = sizeof(clk_id);
msg.content = &clk_id;

reply.hdr = msg.hdr;
reply.len = sizeof(reply_buffer);
reply.content = &reply_buffer;

ret = scmi_send_message(proto, &msg, &reply);
if (ret < 0) {
return ret;
}

if (reply_buffer.status != SCMI_SUCCESS) {
return scmi_status_to_errno(reply_buffer.status);
}

*rate = reply_buffer.rate[0];

return 0;
}

int scmi_clock_config_set(struct scmi_protocol *proto,
struct scmi_clock_config *cfg)
{
struct scmi_message msg, reply;
int status, ret;

/* sanity checks */
if (!proto || !cfg) {
return -EINVAL;
}

if (proto->id != SCMI_PROTOCOL_CLOCK) {
return -EINVAL;
}

/* extended attributes currently not supported */
if (cfg->attributes & SCMI_CLK_CONFIG_EA_MASK) {
return -ENOTSUP;
}

/* invalid because extended attributes are not supported */
if (SCMI_CLK_CONFIG_ENABLE_DISABLE(cfg->attributes) == 3) {
return -ENOTSUP;
}

/* this is a reserved value */
if (SCMI_CLK_CONFIG_ENABLE_DISABLE(cfg->attributes) == 2) {
return -EINVAL;
}

msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_CLOCK_CONFIG_SET,
SCMI_COMMAND, proto->id, 0x0);
msg.len = sizeof(*cfg);
msg.content = cfg;

reply.hdr = msg.hdr;
reply.len = sizeof(status);
reply.content = &status;

ret = scmi_send_message(proto, &msg, &reply);
if (ret < 0) {
return ret;
}

if (status != SCMI_SUCCESS) {
return scmi_status_to_errno(status);
}

return 0;
}

int scmi_clock_protocol_attributes(struct scmi_protocol *proto, uint32_t *attributes)
{
struct scmi_message msg, reply;
struct scmi_clock_attributes_reply reply_buffer;
int ret;

/* sanity checks */
if (!proto || !attributes) {
return -EINVAL;
}

if (proto->id != SCMI_PROTOCOL_CLOCK) {
return -EINVAL;
}

msg.hdr = SCMI_MESSAGE_HDR_MAKE(SCMI_CLK_MSG_PROTOCOL_ATTRIBUTES,
SCMI_COMMAND, proto->id, 0x0);
/* command has no parameters */
msg.len = 0x0;
msg.content = NULL;

reply.hdr = msg.hdr;
reply.len = sizeof(reply_buffer);
reply.content = &reply_buffer;

ret = scmi_send_message(proto, &msg, &reply);
if (ret < 0) {
return ret;
}

if (reply_buffer.status != 0) {
return scmi_status_to_errno(reply_buffer.status);
}

*attributes = reply_buffer.attributes;

return 0;
}
27 changes: 27 additions & 0 deletions dts/bindings/firmware/arm,scmi-clock.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0

description: System Control and Management Interface (SCMI) clock protocol

compatible: "arm,scmi-clock"

include: [base.yaml, clock-controller.yaml]

properties:
shmem:
type: phandles

reg:
required: true
const: [0x14]

"#clock-cells":
required: true
const: 1
description: |
Vendor-specific clock identifier. Needs to match identifier
expected by the SCMI platform as this is directly used in SCMI
clock management messages.
clock-cells:
- name
Loading

0 comments on commit 350e36a

Please sign in to comment.