SCICLIENT

Device AM62x fall under the K3 SoC family and has a concept of centralized Power, Resource and Security management to allow mitigating the challenges of the traditional approach to system control. System Firmware (hereafter referred to as SYSFW) is the collective name for the TI foundational security(TIFS) and device management firmware (DM firmware) which offers these centralized services. In this concept a processing unit (for example an M4F) can request the DM firmware to control power, grant resources or provide secure services. This is done via a special messaging channel called a secure proxy. The messages are sent obeying a proprietary protocol called TISCI (TI System Controller Interface) protocol. For more information on TISCI protocol you can refer to the TISCI Public Documentation.

Sciclient as a software block has multiple functional sub-blocks inside it, as shown in the below image: Sciclient Sub-blocks

More details on the APIs provided on these layers can be found in the API section, linked towards the end of this page.

Generally speaking, the Sciclient driver provides API to communicate with the SYSFW using the TISCI protocol. As mentioned above, this would be for system level tasks like resource allocation, peripheral power on/off, peripheral clock setting, secure services and so on. The sciclient will be part of the application code running on each core. Typical Sciclient Operation

The above image shows the operation for only one core, but the same thing happens for all the cores. SYSFW deals with all the requests coming from each of the cores.

Sciclient is mostly used by other drivers, like DMA, GPIO etc. Sciclient acts as an interface to the SYSFW for these drivers when they need say a resource like DMA channel, or configure an interrupt route. Below are the high level features supported by the driver:

Features Supported

  • Abstracted APIs for Power and Resource Management

  • APIs for Processor Boot including secure boot

  • APIs for configuring firewalls

  • Ability to change and re-build the board configuration data

  • Ability to sign the board configuration blobs for HS devices

SysConfig Features

Note

It is strongly recommend to use SysConfig where it is available instead of using direct SW API calls. This will help simplify the SW application and also catch common mistakes early in the development cycle.

  • There are no user programmable features for Sciclient SysConfig. However, adding any module makes the PowerClock_init() initialize the module power and clock. This is indirectly done using Sciclient APIs.

Features NOT Supported

NA

Important Usage Guidelines

  • Sciclient is mostly used by other peripheral drivers, and mostly not directly by an application. From an application point of view, major usage of Sciclient APIs would be to power on/off a module, set/get the clock of a module, etc.

Board Configuration Overview

SYSFW Board Config files in the sciclient driver is a SOC specific configuration data regarding the various system attributes controlled by the SYSFW. These include resources, power and clock, security etc. This configuration is sent to SYSFW during boot time. The default configuration is stored in source/drivers/sciclient/sciclient_defaultBoardCfg/{{ VAR_SOC_NAME_LOWER }}/

  • Default Boardcfg - sciclient_defaultBoardcfg.c

  • Resource Management BoardCfg - sciclient_defaultBoardCfg_rm.c

  • Power Management BoardCfg - sciclient_defaultBoardCfg_pm.c

  • Security BoardCfg - sciclient_defaultBoardCfg_security.c

The user can change the board configuration data based on their requirement and rebuild the board configuration by following the steps in SYSFW Board Config Generation.

Refer SYSFW board config documentation

Enforcing Processor Access Control List

  • The Access Control List(ACL) for a processor can be set using the Security Boardcfg data. There can be one primary host and three secondary hosts that can control a processor.

  • For example, set the WKUP-R5 core as primary host and A53 core as secondary host for ACL of MCU-R5 processor in the source/drivers/sciclient/sciclient_defaultBoardCfg/{{ VAR_SOC_NAME_LOWER }}/sciclient_defaultBoardCfg_security.c file.

.proc_acl_entries = {
{
    .processor_id = SCICLIENT_PROC_ID_MCU_R5FSS0_CORE0,
    .proc_access_master = TISCI_HOST_ID_MAIN_0_R5_0,
    .proc_access_secondary = {TISCI_HOST_ID_A53_0, TISCI_HOST_ID_TIFS, TISCI_HOST_ID_TIFS},
},
/* set the remaining entries to zero */
{
    0,
},
.
.
.
{
    0,
},
},

Example Usage

Include the below file to access the APIs

#include <stdio.h>
#include <drivers/sciclient.h>

Module Power ON Example

    int32_t  status = SystemP_SUCCESS;
    uint32_t moduleId = TISCI_DEV_TIMER0;
    uint32_t moduleState, resetState, contextLossState;

    /* Check the module status. Need not do power on if it's already ON */
    status = Sciclient_pmGetModuleState(moduleId,
                                        &moduleState,
                                        &resetState,
                                        &contextLossState,
                                        SystemP_WAIT_FOREVER);
    DebugP_assert(SystemP_SUCCESS == status);
    if(moduleState == TISCI_MSG_VALUE_DEVICE_HW_STATE_OFF)
    {
        status = Sciclient_pmSetModuleState(moduleId,
                                            TISCI_MSG_VALUE_DEVICE_SW_STATE_ON,
                                            (TISCI_MSG_FLAG_AOP |
                                             TISCI_MSG_FLAG_DEVICE_EXCLUSIVE |
                                             TISCI_MSG_FLAG_DEVICE_RESET_ISO),
                                             SystemP_WAIT_FOREVER);
        DebugP_assert(status == SystemP_SUCCESS);

        status = Sciclient_pmSetModuleRst (moduleId,
                                               0x0U,
                                               SystemP_WAIT_FOREVER);
        DebugP_assert(status == SystemP_SUCCESS);
    }

Interrupt configuration Example

Since interrupt router outputs are shared resources, we need Sciclient to configure interrupt routers for certain peripherals like GPIO. Here is a snippet explaining this with an example of configuring a GPIO interrupt. For more details on the ideas used below, refer AM64x/AM243x TRM Chapter 9 on interrupts. The INTRTR Integration subsection explains the routing with a diagram.

Interrupt configuration Example

Since interrupt router outputs are shared resources, we need Sciclient to configure interrupt routers for certain peripherals like GPIO. Here is a snippet explaining this with an example of configuring a GPIO interrupt. For more details on the ideas used below, refer AM62x TRM Chapter 9 on interrupts.

Interrupt configuration Example

Since interrupt router outputs are shared resources, we need Sciclient to configure interrupt routers for certain peripherals like GPIO. Here is a snippet explaining this with an example of configuring a GPIO interrupt. For more details on the ideas used below, refer AM62Ax TRM Chapter 9 on interrupts.

    struct tisci_msg_rm_irq_set_req     rmIrqReq;
    struct tisci_msg_rm_irq_set_resp    rmIrqResp;

    /* Here we specify the core specific interrupt router number which we want to tie to the GPIO peripheral interrupt.
     * In this example we are considering the MAIN GPIO instance, which 54 interrupt router outputs, out of which first 16
     * are routed to all the R5 cores. Since these are shared resources, we will need to decide before hand which outputs will
     * be used by which core, and specify this in the sciclient_defaultBoardCfg_rm.c file. In the current configuration,
     * outputs 8 and 9 are allocated to R50-0 core, we can choose either of these to configure the interrupt configuration
     */
    uint32_t gpioIntrNumber = CSLR_R5FSS0_CORE0_INTR_MAIN_GPIOMUX_INTROUTER0_OUTP_8;

    /* Among the GPIOMUX_INTRRTR0 input pins, 0:86 comes from GPIO0 and 90:177 from GPIO1. We are configuring GPIO1 pin in this example, so
     * we define a base interrupt number to be used later.
     */
    uint32_t gpioIntrRtrInputGpio1_Base = 90;

    /* The user interrupt button SW5 is tied to interrupt num 54 among the 88 GPIO interrupt lines of GPIO1 instance */
    uint32_t gpioPushButtonPinNum = 54;

    /* For setting the IRQ for GPIO using sciclient APIs, we need to populate
     * a structure, tisci_msg_rm_irq_set_req instantiated above. The definition
     * of this struct and details regarding the struct members can be found in
     * the tisci_rm_irq.h.
     */
    /* Initialize all flags to zero since we'll be setting only a few */
    rmIrqReq.valid_params           = 0U;
    /* Our request has a destination id, so enable the flag for DST ID */
    rmIrqReq.valid_params          |= TISCI_MSG_VALUE_RM_DST_ID_VALID;
    /* DST HOST IRQ is the output index of the interrupt router. We need to make sure this is also enabled as a valid param */
    rmIrqReq.valid_params          |= TISCI_MSG_VALUE_RM_DST_HOST_IRQ_VALID;
    /* This is not a global event */
    rmIrqReq.global_event           = 0U;
    /* Our interrupt source would be the GPIO peripheral. The source id has to be a device id recognizable by the SYSFW.
     * The list of device IDs can be found in tisci_devices.h file under source/drivers/sciclient/include/tisci/am64x_am243x/.
     * In GPIO case there are 3 possible options - TISCI_DEV_GPIO0, TISCI_DEV_GPIO1, TISCI_DEV_MCU_GPIO0. For input interrupt,
     * we need to choose the TISCI_DEV_GPIO1
     */
    rmIrqReq.src_id                 = TISCI_DEV_GPIO1;
    /* This is the interrupt source index within the GPIO peripheral */
    rmIrqReq.src_index              = gpioIntrRtrInputGpio1_Base + GPIO_GET_BANK_INDEX(gpioPushButtonPinNum);
    /* This is the destination of the interrupt, usually a CPU core. Here we choose the TISCI device ID for R5F0-0 core.
     * For a different core, the corresponding TISCI device id has to be provided */
    rmIrqReq.dst_id                 = TISCI_DEV_R5FSS0_CORE0;
    /* This is the output index of the interrupt router. This depends on the core and board configuration */
    rmIrqReq.dst_host_irq           = gpioIntrNumber;
    /* Rest of the struct members are unused for GPIO interrupt */
    rmIrqReq.ia_id                  = 0U;
    rmIrqReq.vint                   = 0U;
    rmIrqReq.vint_status_bit_index  = 0U;
    rmIrqReq.secondary_host         = TISCI_MSG_VALUE_RM_UNUSED_SECONDARY_HOST;

    /* To set the interrupt we now invoke the Sciclient_rmIrqSet function which
     * will find out the route to configure the interrupt and request SYSFW to
     * grant the resource
     */
    if(0 != Sciclient_rmIrqSet(&rmIrqReq, &rmIrqResp, SystemP_WAIT_FOREVER))
    {
        DebugP_log("[Error] Sciclient event config failed!!!\r\n");
        DebugP_assert(FALSE);
    }

Configuring the Flag Field in TISCI Messages

To receive a response message, TISCI_MSG_FLAG_AOP is used in the flag field of the outgoing message. But, if a response is not needed, then the flag field can be set to 0 instead. That being said, setting the flag field to 0 means no response will be returned, even if the message fails.

When sending TISCI messages, it is recommended to avoid directly writing to the generic header in the payload (request.hdr.flags). Instead, we use the Sciclient_service API and pass the field value to the Sciclient request parameter (reqParam.flags).

To utilize the Sciclient_service API, the following components must be defined:

  • TISCI Request - Define an empty TISCI request structure for the TISCI message type and specify the various required fields in it. We can leave the fields of tisci_header structure as empty.

  • TISCI Response - Define an empty TISCI response structure for the TISCI message type.

  • Request Parameters - Define the structure of the Sciclient request message, and specify the following fields in it -

    • Message Type - Specify the type of message being transmitted.

    • Flags - Determine the custom flag options, selecting either TISCI_MSG_FLAG_AOP for messages requiring a response or 0 for messages that do not require a response.

    • Request Payload - Pass the TISCI Request structure.

    • Request Payload Size - Pass the size of the TISCI Request structure.

    • Timeout - Specify the timeout value for the message.

  • Response Parameters - Define the expected structure of the Sciclient response message, and specify the following fields in it -

    • Response Payload - Pass the TISCI Response structure.

    • Response Payload Size - Pass the size of the TISCI Response structure.

The Sciclient_service call will then copy the message type and the flag value specified in the Sciclient request structure (reqParam.flags) into the TISCI Generic Messaging Header (request.hdr.flags) of the TISCI Request message. This enables users to send messages with AOP or empty flag settings without directly manipulating the TISCI Generic Header.

To learn more about the TISCI Generic Messaging Header, refer to the TISCI Generic Messaging Header documentation. And for more information on supported message types and required parameters, refer to the DRV_SCICLIENT_MODULE documentation.

Example -

    int32_t retVal = SystemP_SUCCESS;
    struct tisci_msg_get_device_req request = {0};
    struct tisci_msg_get_device_resp response = {0};
    Sciclient_ReqPrm_t reqParam = {0};

    Sciclient_RespPrm_t respParam = {0};

    request.id = (uint32_t) TISCI_DEV_A53SS0;

    reqParam.messageType    = (uint16_t) TISCI_MSG_GET_DEVICE;
    reqParam.flags          = (uint32_t) 0;    /* We can set this value to either 0 or `TISCI_MSG_FLAG_AOP` */
    reqParam.pReqPayload    = (const uint8_t *) &request;
    reqParam.reqPayloadSize = (uint32_t) sizeof (request);
    reqParam.timeout        = (uint32_t) timeout;

    respParam.flags           = (uint32_t) 0;    /* Populated by the API when `TISCI_MSG_FLAG_AOP` flag is set in the request */
    respParam.pRespPayload    = (uint8_t *) &response;
    respParam.respPayloadSize = (uint32_t) sizeof (response);

    retVal = Sciclient_service(&reqParam, &respParam);
    if(retVal != SystemP_SUCCESS)
    {
        retVal = SystemP_FAILURE;
    }

Note

Setting the flags value to 0 in the request parameter structure using the Sciclient_service API may cause the message to fail.

Enabling Interrupt Mode

Sciclient can operate in two modes for processing TISCI messages:

  • Polling Mode (Default): The driver polls for the response from SYSFW/DM after sending a request. This is the default mode.

  • Interrupt Mode: The driver uses interrupts to detect when a response is available, allowing the CPU to perform other tasks while waiting.

To switch the mode to Interrupt Mode, follow the steps below:

  • Add the line -DENABLE_SCICLIENT_INTERRUPT_MODE \ to DEFINES_common in source/drivers/makefile.am62dx.r5f.ti-arm-clang.

  • Rebuild the libraries and application.

API Reference

This file contains prototypes for APIs contained as a part of SCICLIENT as well as the structures of their arguments.

The Sciclient_loadFirmware API is used to cater to the first requirement and the Sciclient_service is used to cater to the second. The SCIClient library requires initialization of the a handle which is used by the subsequent API calls. This handle is initialized by the Sciclient_init function. Once the application/higher level software is being torn down or exiting the Sciclient_deinit can be used to de-initialize this handle.

The SCIClient can operate in the following combinations:

  1. Non-OS, Polling based message completion.

  2. Non-OS, Interrupt Based message completion.

  3. RTOS, Polling based message completion.

  4. RTOS, Interrupt based message completion.

The SCIClient depends on the OSAL layer to differentiate between the Non-OS and the RTOS implementation of Semaphores and Interrupts (HWIs). The build parameter of the OSAL library would determine if the application is bare metal or RTOS based. The polling versus interrupt based wait for message completion is a run time configuration passed during the Sciclient_init initialization.

All the APIs for interacting with the firmware are blocking with a specified timeout . A common API Sciclient_service is implemented for all types of calls to the firmware which takes 2 arguments :

The API serves a particular request, based on the value of messageType parameter in Sciclient_ReqPrm_t, whose response is given to the higher level API through Sciclient_RespPrm_t. The Sciclient_ReqPrm_t contains the required inputs from the higher level software corresponding to the message_type, timeout value and the core message as a byte stream. A pointer Sciclient_RespPrm_t has to be passed to the sciclient, which shall be modified by sciclient.

The Sciclient shall be responsible for abstracting all interaction with the secure proxy and the ring accelerator.

Unnamed Group

TISCI_BIT(n)
DEVGRP_ALL

SoC SYSFW devgrp any: NOT TO BE used for SoC data. This implies that specific sequenced devgrp is NOT used

DEVGRP_00

SoC defined SYSFW devgrp 00

DEVGRP_01

SoC defined SYSFW devgrp 01

DEVGRP_02

SoC defined SYSFW devgrp 02

DEVGRP_03

SoC defined SYSFW devgrp 03

DEVGRP_04

SoC defined SYSFW devgrp 04

DEVGRP_05

SoC defined SYSFW devgrp 05

DEVGRP_06

SoC defined SYSFW devgrp 06

DEVGRP_DMSC

SYSFW internal usage ONLY Module belonging solely to DMSC operations

DEVGRP_DMSC_ALL

Match everything - STRICTLY INTERNAL USAGE ONLY

MAX_NUM_DEVGRPS

Maximum number of devgrps that are supported by SYSFW. Derived from the above definitions

typedef uint8_t domgrp_t

Defines the sysfw DOMGRP type. This is meant to be used in code or data structures that require distinction of domgrps.

typedef uint8_t devgrp_t

Defines the sysfw DEVGRP type. This is meant to be used in code or data structures that require distinction of devgrps.

int32_t Sciclient_loadFirmware(const uint32_t *pSciclient_firmware)

Loads the DMSC firmware. This is typically called by SBL. Load firmware does not require calling the Sciclient_init function.

Parameters:

pSciclient_firmware – [IN] Pointer to signed SYSFW binary

Returns:

CSL_PASS on success, else failure

int32_t Sciclient_init(uint32_t coreId)

This API is called once for registering interrupts and creating semaphore handles to be able to talk to the firmware. The application should assume that the firmware is pre-loaded while calling the Sciclient_init API. The firmware should have been loaded either via GEL or via the SBL prior to the application calling the Sciclient_init. If a void pointer is passed, default values will be used, else the values passed will be used.

Parameters:

coreId – [IN] ID of the core running the driver

Returns:

CSL_PASS on success, else failure

int32_t Sciclient_service(const Sciclient_ReqPrm_t *pReqPrm, Sciclient_RespPrm_t *pRespPrm)

This API allows communicating with the System firmware which can be called to perform various functions in the system. Core sciclient function for transmitting payload and recieving the response. The caller is expected to allocate memory for the input request parameter (Refer Sciclient_ReqPrm_t). This involves setting the message type being communicated to the firmware, the response flags, populate the payload of the message based on the inputs in the files sciclient_fmwPmMessages.h,sciclient_fmwRmMessages.h, sciclient_fmwSecMessages.h and sciclient_fmwCommonMessages.h. Since the payload in considered a stream of bytes in this API, the caller should also populate the size of this stream in reqPayloadSize. The timeout is used to determine for what amount of iterations the API would wait for their operation to complete.

To make sure the response is captured correctly the caller should also allocate the space for Sciclient_RespPrm_t parameters. The caller should populate the pointer to the pRespPayload and the size respPayloadSize. The API would populate the response flags to indicate any firmware specific errors and also populate the memory pointed by pRespPayload till the size given in respPayloadSize.

Parameters:
Returns:

CSL_PASS on success, else failure

int32_t Sciclient_deinit(void)

De-initialization of sciclient. This de-initialization is specific to the application. It only de-initializes the semaphores, interrupts etc. which are initialized in Sciclient_init. It does not de-initialize the system firmware.

Returns:

CSL_PASS on success, else failure

int32_t Sciclient_updateOperModeToInterrupt(void)

API to enable interrupt mode for sciclient operations. By default, sciclient operates in polling mode. This function switches sciclient to interrupt mode where message responses trigger interrupts instead of polling. This improves performance and reduces CPU usage.

Returns:

CSL_PASS on success, else failure

void Sciclient_updateOperModeToPolled(void)

API to disable interrupt mode and switch back to polling mode. This function deconfigures interrupts and switches sciclient back to polling mode. All registered ISRs are unregistered and semaphores are destroyed.

void Sciclient_disableIntr(void)

API to temporarily disable interrupts without unregistering. This function disables the secure proxy response interrupt at the interrupt controller level. The interrupt can be re-enabled using Sciclient_enableIntr(). This is useful when temporarily suspending interrupt handling without fully switching back to polling mode.

Note: Only has effect when already in interrupt mode.

void Sciclient_enableIntr(void)

API to re-enable interrupts after Sciclient_disableIntr(). This function re-enables the secure proxy response interrupt that was previously disabled with Sciclient_disableIntr().

Note: Only has effect when already in interrupt mode.

int32_t Sciclient_abiCheck(void)

API to verify that firmware ABI matches the supported ABI.

Returns:

SystemP_SUCCESS on success, else failure

int32_t Sciclient_triggerSecHandover(void)

API to trigger security handover.

Returns:

SystemP_SUCCESS on success, else failure

int32_t Sciclient_getVersionCheck(uint32_t doLog)

API to send a get version command to SYSFW and optionally log the results to console.

Parameters:

doLog – [in] 0: No logging to console, 1: log version results to console

Returns:

SystemP_SUCCESS on success, else failure

int32_t Sciclient_getDMVersion(uint32_t doLog)

API to send a get version command to DM and optionally log the results to console.

API to get the TISCI Device ID of the core on which driver is currently running.

Parameters:

doLog – [in] 0: No logging to console, 1: log version results to console

Returns:

SystemP_SUCCESS on success, else failure

Returns:

TISCI Dev ID of the core

uint32_t Sciclient_getSelfDevIdCore(void)
int32_t Sciclient_waitForBootNotification(void)

Waits for boot notification from SYSFW.

Returns:

SystemP_SUCCESS on success, else failure

struct Sciclient_ReqPrm_t
#include <sciclient.h>

Input parameters for Sciclient_service function.

Public Members

uint16_t messageType

[IN] Type of message.

uint32_t flags

[IN] Flags for messages that are being transmitted.

const uint8_t *pReqPayload

[IN] Pointer to the payload to be transmitted

uint32_t reqPayloadSize

[IN] Size of the payload to be transmitted (in bytes)

uint32_t timeout

[IN] Timeout(number of iterations) for receiving response (Refer SystemP_Timeout)

struct Sciclient_RespPrm_t
#include <sciclient.h>

Output parameters for Sciclient_service function.

Public Members

uint32_t flags

[OUT] Flags of response to messages.

uint8_t *pRespPayload

[IN] Pointer to the received payload. The pointer is an input. The API will populate this with the firmware response upto the size mentioned in respPayloadSize. Please ensure respPayloadSize bytes are allocated.

uint32_t respPayloadSize

[IN] Size of the response payload(in bytes)