TISCI PM Clock API Documentation

Introduction

This document describes the TISCI API set for configuring and controlling the clocks within the system.

Clock configuration and control APIs

TISCI Message ID Message Name
0x0100 TISCI_MSG_SET_CLOCK
0x0101 TISCI_MSG_GET_CLOCK
0x0102 TISCI_MSG_SET_CLOCK_PARENT
0x0103 TISCI_MSG_GET_CLOCK_PARENT
0x0104 TISCI_MSG_GET_NUM_CLOCK_PARENTS
0x010c TISCI_MSG_SET_FREQ
0x010d TISCI_MSG_QUERY_FREQ
0x010e TISCI_MSG_GET_FREQ

Note

Reference Chapter 5: SoC Family Specific Documentation to see clock IDs and device IDs for your SoC.

Note

The SSC controls are not yet available in the system firmware.

Macros Used in this Document

TISCI_MSG_VALUE_CLOCK_SW_STATE_UNREQ          0

The IP does not require this clock, it can be disabled, regardless of the state of the device

TISCI_MSG_VALUE_CLOCK_SW_STATE_AUTO          1

Allow the system controller to automatically manage the state of this clock. If the device is enabled, then the clock is enabled. If the device is set to off or retention, then the clock is internally set as not being required by the device. This is the default state.

TISCI_MSG_VALUE_CLOCK_SW_STATE_REQ          2

Configure the clock to be enabled, regardless of the state of the device.

TISCI_MSG_VALUE_CLOCK_HW_STATE_NOT_READY          0

Indicate hardware state of the clock is that it is not running.

TISCI_MSG_VALUE_CLOCK_HW_STATE_READY          1

Indicate hardware state of the clock is that it is running.

TISCI_MSG_FLAG_CLOCK_ALLOW_SSC          BIT(8)

Allow this clock to be modified via spread spectrum clocking. note: The SSC feature is currently not supported in System Firmware.

TISCI_MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE          BIT(9)

Allow this clock’s frequency to be changed while it is running so long as it is within the min/max limits.

TISCI_MSG_FLAG_CLOCK_INPUT_TERM          BIT(10)

Enable input termination, this is only applicable to clock inputs on the SoC pseudo-device, BOARD0.

TISCI_MSG_FLAG_CLOCK_SSC_ACTIVE          BIT(11)

Indicate that SSC is active for this clock. note: The SSC feature is currently not supported in System Firmware.

Large Clock Index Compatibility

Clock indexes identify clocks connected to devices. There are typically a small number of clocks connected to each device. The original API was designed with an 8-bit field to represent clock indexes allowing a maximum clock index of 254, which 255 being reserved to indicate an invalid clock index.

The number of clocks connected to devices on newer SoCs has multiplied rapidly and has exceeded the 254 limit, largely due to very wide input muxes. The API has been extended to support these larger clock indexes while still remaining forward and reverse compatible. This change requires some action by users of the API when indexes larger than 254 are present.

For each clock index within a message a 32-bit field has been appended to the end of the message. If a clock index is less than or equal to 254, the extra field is unused and the clock index is stored in the original 8-bit field. If the clock index is 255 or larger, the value 255 is stored is the original 8-bit field and the actual value is stored in the extra 32-bit field. This applies to both requests and responses from the firmware.

Note that if a host with large clock index support attempts to send a clock index 255 or greater to a firmware without large clock index support, the firmware will interpret the 255 value in the 8-bit clock index field as invalid and NAK the request. Similarly, if a request is made that requires the firmware to respond with a value 255 or greater (such as the number of clock parents) the firmware will return a NAK. If a host without large clock index support makes a request that requires a firmware with large clock index support to respond with a value of 255 or greater it will return an ACK but place 255 in the 8-bit field. This should be interpreted by the host as an invalid clock index.

The host can also request the ABI version. ABI versions prior to 2.6 lack large clock index support.

TISCI_MSG_SET_CLOCK

Objective

Setup a hardware device’s clock state

Usage

Message Type Normal
Secure Queue Only? No

This requests for finer control of hardware device’s clocks. This allows for configuration for hardware blocks that require customization of the specific input clocks. NOTE: each of the clock IDs are relative to the hardware block.

TISCI Message ID

TISCI_MSG_SET_CLOCK          (0x0100U)

Message Data Structures

struct tisci_msg_set_clock_req

Mark a clock as required/not required.

Parameter Type Description
hdr struct tisci_header TISCI header
device u32 The device ID that the clock is connected to.
clk u8 Each device has its own set of clock inputs. This indexes which clock input to modify.
clk32 u32 Stores the actual clock index if clk field is set to 255. This field is ignored otherwise. This field can hold the full range of possible clock indexes, but for compatibility with older firmwares should only be used when the index is 255 or greater.
state u8 The desired state of the clock, TISCI_MSG_VALUE_CLOCK_SW_STATE_REQ if the clock is currently required by the IP and TISCI_MSG_VALUE_CLOCK_SW_STATE_UNREQ if it is not. TISCI_MSG_VALUE_CLOCK_SW_STATE_AUTO enables the clock when the IP is set to enabled and disables it when the IP is set to disabled. This is the default state.

Indicate that the selected clock is currently required/not required by the IP. Certain flags can be set in the message header for device clocks: TISCI_MSG_FLAG_CLOCK_ALLOW_SSC, TISCI_MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE, TISCI_MSG_FLAG_CLOCK_INPUT_TERM. If the clock index is 255 or greater, this field should be set to 255 and the full value placed in the clk32 field. This is kept for backwards compatibility with older firmwares.

struct tisci_msg_set_clock_resp

Empty response for TISCI_MSG_SET_CLOCK

Parameter Type Description
hdr struct tisci_header TISCI header to provide ACK/NAK flags to the host.

Although this message is essentially empty and contains only a header a full data structure is created for consistency in implementation.

TISCI_MSG_GET_CLOCK

Objective

Get the state of a clock to or from a hardware block.

Usage

Message Type Normal
Secure Queue Only? No

This requests for additional information about the state of a clock within the system including the state it is programmed to and the actual state of the clock.

TISCI Message ID

TISCI_MSG_GET_CLOCK          (0x0101U)

Message Data Structures

struct tisci_msg_get_clock_req

Get the current state of a clock

Parameter Type Description
hdr struct tisci_header TISCI header
device u32 The device ID that the clock is connected to.
clk u8 Each device has its own set of clock inputs. This indexes which clock input to get.
clk32 u32 Stores the actual clock index if clk field is set to 255. This field is ignored otherwise. This field can hold the full range of possible clock indexes, but for compatibility with older firmwares should only be used when the index is 255 or greater.

If the clock index is 255 or greater, this field should be set to 255 and the full value placed in the clk32 field. This is kept for backwards compatibility with older firmwares.

struct tisci_msg_get_clock_resp

Clock state response.

Parameter Type Description
hdr struct tisci_header TISCI header
programmed_state u8 The programmed state as set by the set message.
current_state u8 The actual state of the clock. If it is desired that a clock be on, it is usually better to send a set message with a flag indicating that an ack be sent when the message is processed rather than attempting to poll this state.

TISCI_MSG_SET_CLOCK_PARENT

Objective

SoC specific customization for setting up a specific clock parent ID for the various clock input options for a hardware block’s clock.

Usage

Message Type Normal
Secure Queue Only? No

This is rarely used customization that may be required based on the usecase of the system where the reset input clock option may not suffice for the usecase attempted.

Message ID

TISCI_MSG_SET_CLOCK_PARENT          (0x0102U)

Message Data Structures

struct tisci_msg_set_clock_parent_req

Set the clock parent

Parameter Type Description
hdr struct tisci_header TISCI header
device u32 The device ID that the clock is connected to.
clk u8 Each device has its own set of clock inputs. This indexes which clock input to modify.
clk32 u32 Stores the actual clock index if clk field is set to 255. This field is ignored otherwise. This field can hold the full range of possible clock indexes, but for compatibility with older firmwares should only be used when the index is 255 or greater.
parent u8 The new clock parent is selectable by an index via this parameter.
parent32 u32 Stores the actual parent clock index if parent field is set to 255. This field is ignored otherwise. This field can hold the full range of possible parent clock indexes, but for compatibility with older firmwares should only be used when the index is 255 or greater.

Many IPs have a mux external to the IP that can select among different clock sources. The clock must be disabled (TISCI_MSG_VALUE_CLOCK_SW_STATE_UNREQ) for this message to succeed. If a set frequency command is not issued before the clock is enabled again, then the execution of the enable command will attempt to set the new parent to the old parent’s frequency. If this fails, then the enable will fail. Muxes that provide clocks to multiple devices are not currently configurable via this API. If the clock index is 255 or greater, this field should be set to 255 and the full value placed in the clk32 field. This is kept for backwards compatibility with older firmwares. If the parent clock index is 255 or greater, this field should be set to 255 and the full value placed in the parent32 field. This is kept for backwards compatibility with older firmwares.

struct tisci_msg_set_clock_parent_resp

Empty response for TISCI_MSG_SET_CLOCK_PARENT

Parameter Type Description
hdr struct tisci_header TISCI header to provide ACK/NAK flags to the host.

Although this message is essentially empty and contains only a header a full data structure is created for consistency in implementation.

TISCI_MSG_GET_CLOCK_PARENT

Objective

Query the clock parent currently configured for a specific clock source of a hardware block

Usage

Message Type Normal
Secure Queue Only? No

This is typically used to confirm the current clock parent to ensure that the requisite usecase for the hardware block can be satisfied. Note that if the programmed value in the underlying hardware is invalid, a NAK is returned for this message. Once a valid parent is programmed via a successful TISCI_MSG_SET_CLOCK_PARENT call, calls to TISCI_MSG_GET_CLOCK_PARENT will succeed.

Message ID

TISCI_MSG_GET_CLOCK_PARENT          (0x0103U)

Message Data Structures

struct tisci_msg_get_clock_parent_req

Return the current clock parent

Parameter Type Description
hdr struct tisci_header TISCI header
device u32 The device ID that the clock is connected to.
clk u8 Each device has its own set of clock inputs. This indexes which clock input to get.
clk32 u32 Stores the actual clock index if clk field is set to 255. This field is ignored otherwise. This field can hold the full range of possible clock indexes, but for compatibility with older firmwares should only be used when the index is 255 or greater.

If the hardware value indicating the current clock parent contains a reserved value, a NAK is returned for this message. Once a valid parent is programmed via a successful SET_CLOCK_PARENT call, calls to GET_CLOCK_PARENT will succeed. If the clock index is 255 or greater, this field should be set to 255 and the full value placed in the clk32 field. This is kept for backwards compatibility with older firmwares.

struct tisci_msg_get_clock_parent_resp

Clock parent response

Parameter Type Description
hdr struct tisci_header TISCI header
parent u8 The current clock parent.
parent32 u32 Parent Clock index if 255 or greater and parent field is set to 255. This field will contain 0xFFFFFFFF otherwise.

If the parent clock index is 255 or greater, this field will be set to 255 and the full value placed in the parent32 field. This is for backwards compatibility with older firmwares.

TISCI_MSG_GET_NUM_CLOCK_PARENTS

Objective

Query for the number of parent clock paths available for a specific hardware block’s clock.

Usage

Message Type Normal
Secure Queue Only? No

This is typically used to get the max number of clock parent options available for a specific hardware block’s clock.

Message ID

TISCI_MSG_GET_NUM_CLOCK_PARENTS          (0x0104U)

Message Data Structures

struct tisci_msg_get_num_clock_parents_req

Return the number of possible parents for a clock

Parameter Type Description
hdr struct tisci_header TISCI header
device u32 The device ID that the clock is connected to.
clk u8 Each device has its own set of clock inputs. This indexes which clock input to query.
clk32 u32 Stores the actual clock index if clk field is set to 255. This field is ignored otherwise. This field can hold the full range of possible clock indexes, but for compatibility with older firmwares should only be used when the index is 255 or greater.

If the clock index is 255 or greater, this field should be set to 255 and the full value placed in the clk32 field. This is kept for backwards compatibility with older firmwares.

struct tisci_msg_get_num_clock_parents_resp

Num clock parents response

Parameter Type Description
hdr struct tisci_header TISCI header
num_parents u8 The number of clock parents.
num_parents32 u32 Number of clock parents if 255 or greater and num_parents field is set to 255. This field will contain 0xFFFFFFFF otherwise.

If the number of clock parents is 255 or greater, this field will be set to 255 and the full value placed in the num_parents32 field. This is for backwards compatibility with older firmwares.

TISCI_MSG_SET_FREQ

Objective

Setup a clock frequency for a hardware block’s clock.

Usage

Message Type Normal
Secure Queue Only? No

This is typically desired when the default frequency of the hardware block’s clock is not appropriate for the usecase desired.

NOTE: Normally clock frequency management is automatically done by TISCI entity. In case of specific requests, TISCI evaluates capability to achieve requested range and responds with success/failure message.

This sets the desired frequency for a clock within an allowable range. This message will fail on an enabled clock unless MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE is set for the clock. Additionally, if other clocks have their frequency modified due to this message, they also must have the MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE or be disabled.

Calling set frequency on a clock input to the SoC pseudo-device will inform the PMMC of that clock’s frequency. Setting a frequency of zero will indicate the clock is disabled.

Calling set frequency on clock outputs from the SoC pseudo-device will function similarly to setting the clock frequency on a device.

Message ID

TISCI_MSG_SET_FREQ          (0x010cU)

Message Data Structures

struct tisci_msg_set_freq_req

Set the desired frequency for a clock.

Parameter Type Description
hdr struct tisci_header TISCI header
device u32 The device ID that the clock is connected to.
min_freq_hz u64 The minimum allowable frequency in Hz. This is the minimum allowable programmed frequency and does not account for clock tolerances and jitter.
target_freq_hz u64 The target clock frequency. The clock will be programmed at a rate as close to this target frequency as possible.
max_freq_hz u64 The maximum allowable frequency in Hz. This is the maximum allowable programmed frequency and does not account for clock tolerances and jitter. The firmware will actually accept any frequency up to but not including max + 1.
clk u8 Each device has its own set of clock inputs. This indexes which clock input to modify.
clk32 u32 Stores the actual clock index if clk field is set to 255. This field is ignored otherwise. This field can hold the full range of possible clock indexes, but for compatibility with older firmwares should only be used when the index is 255 or greater.

This set the desired frequency for a clock within an allowable range. This message will fail on an enabled clock unless TISCI_MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE is set for the clock. Additionally, if other clocks have their frequency modified due to this message, they also must have the TISCI_MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE or be disabled. Calling set frequency on a clock input to the SoC psuedo-device will inform the PMMC of that clock’s frequency. Setting a frequency of zero will indicate the clock is disabled. Calling set frequency on clock outputs from the SoC pseudo-device will function similarly to setting the clock frequency on a device. If the clock index is 255 or greater, this field should be set to 255 and the full value placed in the clk32 field. This is kept for backwards compatibility with older firmwares.

struct tisci_msg_set_freq_resp

Empty response for TISCI_MSG_SET_FREQ

Parameter Type Description
hdr struct tisci_header TISCI header to provide ACK/NAK flags to the host.

Although this message is essentially empty and contains only a header a full data structure is created for consistency in implementation.

TISCI_MSG_QUERY_FREQ

Objective

Query to find closest match possible for a target frequency.

Usage

Message Type Normal
Secure Queue Only? No

This message does no real operation, instead, it requests the system control entity to respond with the best frequency that can match a frequency range provided.

NOTE: This is a snapshot view. In a multi processing system, it is very well possible that another processing entity might change the configuration after one entity has queried for best match capability. Only a SET_CLOCK_FREQ will guarantee the frequency is configured.

Message ID

TISCI_MSG_QUERY_FREQ          (0x010dU)

Message Data Structures

struct tisci_msg_query_freq_req

Determine the result of a hypothetical set frequency operation.

Parameter Type Description
hdr struct tisci_header TISCI header
device u32 The device ID that the clock is connected to.
min_freq_hz u64 The minimum allowable frequency in Hz. This is the minimum allowable programmed frequency and does not account for clock tolerances and jitter.
target_freq_hz u64 The target clock frequency. A frequency will be found as close to the target frequency as possible.
max_freq_hz u64 The maximum allowable frequency in Hz. This is the maximum allowable programmed frequency and does not account for clock tolerances and jitter. The firmware will actually accept any frequency up to but not including max + 1.
clk u8 Each device has its own set of clock inputs. This indexes which clock input to query.
clk32 u32 Stores the actual clock index if clk field is set to 255. This field is ignored otherwise. This field can hold the full range of possible clock indexes, but for compatibility with older firmwares should only be used when the index is 255 or greater.

This allows the OS to determine what rate would be set given a set of parameters. A nack will be received if a frequency is not available in the given range. If the clock index is 255 or greater, this field should be set to 255 and the full value placed in the clk32 field. This is kept for backwards compatibility with older firmwares.

struct tisci_msg_query_freq_resp

Result of a query operation

Parameter Type Description
hdr struct tisci_header TISCI header
freq_hz u64 The frequency in Hz that the hardware would set for the given parameters.

TISCI_MSG_GET_FREQ

Objective

Get the clock frequency of a specific clock which belongs to a hardware block.

Usage

Message Type Normal
Secure Queue Only? No

This is most used functionality and is meant for usage when the driver controlling the hardware block requires to know the input clock frequency for configuring internal dividers / multipliers as required.

Message ID

TISCI_MSG_GET_FREQ          (0x010eU)

Message Data Structures

struct tisci_msg_get_freq_req

Get the current frequency of a device’s clock

Parameter Type Description
hdr struct tisci_header TISCI header
device u32 The device ID that the clock is connected to.
clk u8 Each device has its own set of clock inputs. This indexes which clock input to query.
clk32 u32 Stores the actual clock index if clk field is set to 255. This field is ignored otherwise. This field can hold the full range of possible clock indexes, but for compatibility with older firmwares should only be used when the index is 255 or greater.

This message will only succeed if the clock is currently enabled, otherwise it returns nack. If the clock index is 255 or greater, this field should be set to 255 and the full value placed in the clk32 field. This is kept for backwards compatibility with older firmwares.

struct tisci_msg_get_freq_resp

Result of get frequency request

Parameter Type Description
hdr struct tisci_header TISCI header
freq_hz u64 The current frequency in Hz.

Power Management Clock Frequency Configuration Example

Power Management Clock Frequency Configuration without Multiplexers

An example sequence for setting the clock frequency for a given module is as given below. The input to this code snippet is as below:

  • device_id: Refer to the AM6 Devices Descriptions
  • clk_id: Refer to the AM6 Clock Identifiers. Choose the Ids which are marked “Input Clock”.
  • min_hz: Minimum Frequency which should be set for this clock.
  • freq_hz: Target Frequency which should be set for this clock.
  • max_hz: Maximum Frequency which should be set for this clock.

The simplified sequence of operations is as below:

../../_images/Clocks_sequence_diagram.jpg
/* Allocate space for the messages */
u32 tisci_msg_data[13];
/* Pointer to the header */
struct tisci_header *hdr = (struct tisci_header *) tisci_msg_data;
struct tisci_msg_get_freq_req *get_freq_req;
struct tisci_msg_get_freq_resp *get_freq_resp;
struct tisci_msg_set_freq_req *set_freq_req;
struct tisci_msg_query_freq_resp *query_freq_resp;
int ret = 0;

/* Initialize the message data with 0s */
memset(tisci_msg_data, 0, sizeof(tisci_msg_data));
/* Get the current frequency of the device and corresponding clock */
hdr->host = 0x01;
hdr->flags = TISCI_MSG_FLAG_AOP;
/* Message for Getting the frequency for the clock of the device of interest */
hdr->type = TISCI_MSG_GET_FREQ;
get_freq_req = (struct tisci_msg_get_freq_req *) (hdr + 1);
/* Give the device ID from the devices list in the SoC Documentation */
get_freq_req->device = device_id;
/* The clock IDs can be less than 255 or greater than 255. If the clock
 * ID is greater than 255, then set 2 fields in the message.
 */
if (clk_id >= 255) {
    get_freq_req->clk = 255;
    get_freq_req->clk32 = clk_id;
} else {
    get_freq_req->clk = clk_id;
}

/* Send a message to the System firmware on a specific Secure Proxy Queue.
 * The same structure for the message data. The same can be used as the
 * message data is copied to the secure proxy registers.
 */
ret = send_receive_with_timeout(TISCI_MSG_QUEUE_NONSEC_HIGH_TX,
                (void *)tisci_msg_data,
                sizeof(tisci_msg_data),
                (void *)tisci_msg_data, sizeof(tisci_msg_data));

if (ret < 0)
    return ret;

get_freq_resp = (struct tisci_msg_get_freq_resp *) (hdr + 1);
printf("Current: ");
print_freq(get_freq_resp->freq_hz);
printf("\n");

printf("Sending query: ");
print_freq(min_hz);
printf(", ");
print_freq(freq_hz);
printf(", ");
print_freq(max_hz);
printf("\n");

/* Initialize the message data with 0s */
memset(tisci_msg_data, 0, sizeof(tisci_msg_data));
hdr->host = 0x01;
hdr->flags = TISCI_MSG_FLAG_AOP;
/* Message for querying if the frequency is possible for the clock of the device of interest */
hdr->type = TISCI_MSG_QUERY_FREQ;
set_freq_req = (struct tisci_msg_set_freq_req *) (hdr + 1);
/* Give the device ID from the devices list in the SoC Documentation */
set_freq_req->device = device_id;
/* The clock IDs can be less than 255 or greater than 255. If the clock
 * ID is greater than 255, then set 2 fields in the message.
 */
if (clk_id >= 255) {
    set_freq_req->clk = 255;
    set_freq_req->clk32 = clk_id;
} else {
    set_freq_req->clk = clk_id;
}
set_freq_req->min_freq_hz = min_hz;
set_freq_req->target_freq_hz = freq_hz;
set_freq_req->max_freq_hz = max_hz;

/* Send a message to the System firmware on a specific Secure Proxy Queue.
 * The same structure for the message data. The same can be used as the
 * message data is copied to the secure proxy registers.
 */
ret = send_receive_with_timeout(TISCI_MSG_QUEUE_NONSEC_HIGH_TX,
                (void *)tisci_msg_data,
                sizeof(tisci_msg_data),
                (void *)tisci_msg_data, sizeof(tisci_msg_data));

if (ret == 0 && !(hdr->flags & TISCI_MSG_FLAG_ACK))
    ret = -ENODEV;

if (ret == 0) {
    query_freq_resp = (struct tisci_msg_query_freq_resp *) (hdr + 1);
    printf("Query response: ");
    print_freq(query_freq_resp->freq_hz);
    printf("\n");

    if (query_freq_resp->freq_hz < min_hz || query_freq_resp->freq_hz > max_hz)
        ret = -EINVAL;
}
if (ret < 0)
    return ret;

freq_hz = query_freq_resp->freq_hz;
printf("Sending set: ");
print_freq(freq_hz);
printf(", ");
print_freq(freq_hz);
printf(", ");
print_freq(freq_hz);
printf("\n");

/* Initialize the message data with 0s */
memset(tisci_msg_data, 0, sizeof(tisci_msg_data));
hdr->host = 0x01;
hdr->flags = TISCI_MSG_FLAG_AOP;
/* Message for setting the frequency for the clock of the device of interest. Actually changes the frequency */
hdr->type = TISCI_MSG_SET_FREQ;
set_freq_req = (struct tisci_msg_set_freq_req *) (hdr + 1);
/* Give the device ID from the devices list in the SoC Documentation */
set_freq_req->device = device_id;
/* The clock IDs can be less than 255 or greater than 255. If the clock
 * ID is greater than 255, then set 2 fields in the message.
 */
if (clk_id >= 255) {
    set_freq_req->clk = 255;
    set_freq_req->clk32 = clk_id;
} else {
    set_freq_req->clk = clk_id;
}
set_freq_req->min_freq_hz = freq_hz;
set_freq_req->target_freq_hz = freq_hz;
set_freq_req->max_freq_hz = freq_hz;

/* Send a message to the System firmware on a specific Secure Proxy Queue.
 * The same structure for the message data. The same can be used as the
 * message data is copied to the secure proxy registers.
 */
ret = send_receive_with_timeout(TISCI_MSG_QUEUE_NONSEC_HIGH_TX,
                (void *)tisci_msg_data,
                sizeof(tisci_msg_data),
                (void *)tisci_msg_data, sizeof(tisci_msg_data));

if (ret == 0 && !(hdr->flags & TISCI_MSG_FLAG_ACK))
    ret = -ENODEV;
if (ret < 0)
    return ret;

/* Initialize the message data with 0s */
memset(tisci_msg_data, 0, sizeof(tisci_msg_data));
hdr->host = 0x01;
hdr->flags = TISCI_MSG_FLAG_AOP;
/* Message for Getting the frequency for the clock of the device of interest */
hdr->type = TISCI_MSG_GET_FREQ;
get_freq_req = (struct tisci_msg_get_freq_req *) (hdr + 1);
/* Give the device ID from the devices list in the SoC Documentation */
get_freq_req->device = device_id;
/* The clock IDs can be less than 255 or greater than 255. If the clock
 * ID is greater than 255, then set 2 fields in the message.
 */
if (clk_id >= 255) {
    get_freq_req->clk = 255;
    get_freq_req->clk32 = clk_id;
} else {
    get_freq_req->clk = clk_id;
}

/* Send a message to the System firmware on a specific Secure Proxy Queue.
 * The same structure for the message data. The same can be used as the
 * message data is copied to the secure proxy registers.
 */
ret = send_receive_with_timeout(TISCI_MSG_QUEUE_NONSEC_HIGH_TX,
                (void *)tisci_msg_data,
                sizeof(tisci_msg_data),
                (void *)tisci_msg_data, sizeof(tisci_msg_data));

if (ret == 0) {
    get_freq_resp = (struct tisci_msg_get_freq_resp *) (hdr + 1);
    printf("New: ");
    print_freq(get_freq_resp->freq_hz);
    printf("\n");

    if (freq_hz != get_freq_resp->freq_hz)
        ret = -EINVAL;
}
if (ret < 0)
    return ret;

Power Management Clock Frequency Configuration Example with Mux programming

An example pseudo sequence for setting the clock frequency while searching for the right multiplexer parent is as below:

  • device_id: Refer to the AM6 Devices Descriptions
  • clk_id: Refer to the AM6 Clock Identifiers. Choose the Ids which are marked “Input Clock”.
  • min_hz: Minimum Frequency which should be set for this clock.
  • freq_hz: Target Frequency which should be set for this clock.
  • max_hz: Maximum Frequency which should be set for this clock.

The flow chart for the same is as below:

../../_images/pm_clocks_example.svg
/* Check if the clock is enabled or not */
status = TISCI_MSG_GET_CLOCK(device_id,
                             clk_id,
                             &clockStatus);
if (status == PASS)
{
    /* Get the number of parents for the clock */
    status = TISCI_MSG_GET_NUM_CLOCK_PARENTS(device_id,
                                            clk_id,
                                            &numParents);
    if ((status == PASS) && (numParents > 1U))
    {
        status = TISCI_MSG_GET_CLOCK_PARENT(device_id, clk_id, &origParent);
    }
}
if (status == PASS)
{
    /* Disabling the clock */
    status = TISCI_MSG_SET_CLOCK(device_id,
                                clk_id,
                                TISCI_MSG_VALUE_CLOCK_SW_STATE_UNREQ);
}
if (status == PASS)
{
    foundParent = 0U;
    /* Try to loop and change parents of the clock */
    for(i=0U;i<numParents;i++)
    {
        if (numParents > 1U)
        {
            /* Setting the new parent */
            status = TISCI_MSG_SET_CLOCK_PARENT(
                                        device_id,
                                        clk_id,
                                        clk_id+i+1U);
            /* Check if the clock can be set to desirable freq. */
            if (status == PASS)
            {
                moduleClockParentChanged = 1U;
            }
        }
        if (status == PASS)
        {
            status = TISCI_MSG_QUERY_FREQ(device_id,
                                          clk_id,
                                          freq_hz,
                                          &respfreq_hz);
        }
        if ((status == PASS) && (respfreq_hz == freq_hz))
        {
            foundParent = 1U;
            break;
        }
    }
}
if ((status == PASS) && (numParents == 0U))
{
    status = TISCI_MSG_QUERY_FREQ(device_id,
                                  clk_id,
                                  freq_hz,
                                  &respfreq_hz);
    if ((status == PASS) && (respfreq_hz == freq_hz))
    {
        foundParent = 1U;
    }
}
if (foundParent == 1U)
{
    /* Set the clock at the desirable frequency*/
    status = TISCI_MSG_SET_FREQ(
                            device_id,
                            clk_id,
                            freq_hz,
                            TISCI_MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE);
}
else
{
    status = CSL_EFAIL;
}
if ((status == PASS) &&
    (clockStatus == (uint32_t) TISCI_MSG_VALUE_CLOCK_SW_STATE_UNREQ))
{
    /* Restore the clock again to original state */
    status = TISCI_MSG_SET_CLOCK(
                                 device_id,
                                 clk_id,
                                 clockStatus);
}
finalStatus = status;
if ((status != PASS) && (moduleClockParentChanged == 1U))
{
    /* Setting the original parent if failure */
    (void) TISCI_MSG_SET_CLOCK_PARENT(
                                device_id,
                                clk_id,
                                origParent);
}