forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
firmware: scmi: add support for clock management protocol
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
1 parent
413c77c
commit 350e36a
Showing
9 changed files
with
398 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.