Commit 487c869d authored by davidcunado-arm's avatar davidcunado-arm Committed by GitHub
Browse files

Merge pull request #1088 from soby-mathew/sm/sds_scmi

Introduce SDS Driver
parents 800a55ea 18e279eb
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <platform_def.h>
#include "../sds.h"
#include "../sds_private.h"
.globl sds_get_primary_cpu_id
/*
* int sds_get_primary_cpu_id(void);
* Return the primary CPI ID from SDS Structure
* Returns CPUID on success or -1 on failure
*/
func sds_get_primary_cpu_id
mov_imm x0, PLAT_ARM_SDS_MEM_BASE
mov w2, #SDS_REGION_SIGNATURE
ldr w1, [x0]
/* Check if the SDS region signature found */
cmp w2, w1, uxth
b.ne 2f
/* Get the structure count from region descriptor in `w1 */
ubfx w1, w1, #SDS_REGION_STRUCT_COUNT_SHIFT, #SDS_REGION_STRUCT_COUNT_WIDTH
cbz w1, 2f
add x0, x0, #SDS_REGION_DESC_SIZE
/* Initialize the loop iterator count in w3 */
mov w3, #0
loop_begin:
ldrh w2, [x0]
cmp w2, #SDS_AP_CPU_INFO_STRUCT_ID
b.ne continue_loop
/* We have found the required structure */
ldr w0, [x0,#(SDS_HEADER_SIZE + SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET)]
ret
continue_loop:
/* Increment the loop counter and exit loop if counter == structure count */
add w3, w3, #0x1
cmp w1, w3
b.eq 2f
/* Read the 2nd word in header */
ldr w2, [x0,#4]
/* Get the structure size from header */
ubfx x2, x2, #SDS_HEADER_STRUCT_SIZE_SHIFT, #SDS_HEADER_STRUCT_SIZE_WIDTH
/* Add the structure size and SDS HEADER SIZE to point to next header */
add x2, x2, #SDS_HEADER_SIZE
add x0, x0, x2
b loop_begin
2:
mov w0, #0xffffffff
ret
endfunc sds_get_primary_cpu_id
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <debug.h>
#include <css_def.h>
#include <stdint.h>
#include <string.h>
#include "sds.h"
#include "sds_private.h"
/*
* Variables used to track and maintain the state of the memory region reserved
* for usage by the SDS framework.
*/
/* Pointer to the base of the SDS memory region */
static uintptr_t sds_mem_base;
/* Size of the SDS memory region in bytes */
static size_t sds_mem_size;
/*
* Perform some non-exhaustive tests to determine whether any of the fields
* within a Structure Header contain obviously invalid data.
* Returns SDS_OK on success, SDS_ERR_FAIL on error.
*/
static int sds_struct_is_valid(uintptr_t header)
{
size_t struct_size = GET_SDS_HEADER_STRUCT_SIZE(header);
/* Zero is not a valid identifier */
if (GET_SDS_HEADER_ID(header) == 0)
return SDS_ERR_FAIL;
/* Check SDS Schema version */
if (GET_SDS_HEADER_VERSION(header) == SDS_REGION_SCH_VERSION)
return SDS_ERR_FAIL;
/* The SDS Structure sizes have to be multiple of 8 */
if ((struct_size == 0) || ((struct_size % 8) != 0))
return SDS_ERR_FAIL;
if (struct_size > sds_mem_size)
return SDS_ERR_FAIL;
return SDS_OK;
}
/*
* Validate the SDS structure headers.
* Returns SDS_OK on success, SDS_ERR_FAIL on error.
*/
static int validate_sds_struct_headers(void)
{
unsigned int i, structure_count;
uintptr_t header;
structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
if (structure_count == 0)
return SDS_ERR_FAIL;
header = sds_mem_base + SDS_REGION_DESC_SIZE;
/* Iterate over structure headers and validate each one */
for (i = 0; i < structure_count; i++) {
if (sds_struct_is_valid(header) != SDS_OK) {
WARN("SDS: Invalid structure header detected\n");
return SDS_ERR_FAIL;
}
header += GET_SDS_HEADER_STRUCT_SIZE(header) + SDS_HEADER_SIZE;
}
return SDS_OK;
}
/*
* Get the structure header pointer corresponding to the structure ID.
* Returns SDS_OK on success, SDS_ERR_STRUCT_NOT_FOUND on error.
*/
static int get_struct_header(uint32_t structure_id, struct_header_t **header)
{
unsigned int i, structure_count;
uintptr_t current_header;
assert(header);
structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
if (structure_count == 0)
return SDS_ERR_STRUCT_NOT_FOUND;
current_header = ((uintptr_t)sds_mem_base) + SDS_REGION_DESC_SIZE;
/* Iterate over structure headers to find one with a matching ID */
for (i = 0; i < structure_count; i++) {
if (GET_SDS_HEADER_ID(current_header) == structure_id) {
*header = (struct_header_t *)current_header;
return SDS_OK;
}
current_header += GET_SDS_HEADER_STRUCT_SIZE(current_header) +
SDS_HEADER_SIZE;
}
*header = NULL;
return SDS_ERR_STRUCT_NOT_FOUND;
}
/*
* Check if a structure header corresponding to the structure ID exists.
* Returns SDS_OK if structure header exists else SDS_ERR_STRUCT_NOT_FOUND
* if not found.
*/
int sds_struct_exists(unsigned int structure_id)
{
struct_header_t *header = NULL;
int ret;
ret = get_struct_header(structure_id, &header);
if (ret == SDS_OK) {
assert(header);
}
return ret;
}
/*
* Read from field in the structure corresponding to `structure_id`.
* `fld_off` is the offset to the field in the structure and `mode`
* indicates whether cache maintenance need to performed prior to the read.
* The `data` is the pointer to store the read data of size specified by `size`.
* Returns SDS_OK on success or corresponding error codes on failure.
*/
int sds_struct_read(uint32_t structure_id, unsigned int fld_off,
void *data, size_t size, sds_access_mode_t mode)
{
int status;
uintptr_t field_base;
struct_header_t *header = NULL;
if (!data)
return SDS_ERR_INVALID_PARAMS;
/* Check if a structure with this ID exists */
status = get_struct_header(structure_id, &header);
if (status != SDS_OK)
return status;
assert(header);
if (mode == SDS_ACCESS_MODE_CACHED)
inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
if (!IS_SDS_HEADER_VALID(header)) {
WARN("SDS: Reading from un-finalized structure 0x%x\n",
structure_id);
return SDS_ERR_STRUCT_NOT_FINALIZED;
}
if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
return SDS_ERR_FAIL;
field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
if (check_uptr_overflow(field_base, size - 1))
return SDS_ERR_FAIL;
/* Copy the required field in the struct */
memcpy(data, (void *)field_base, size);
return SDS_OK;
}
/*
* Write to the field in the structure corresponding to `structure_id`.
* `fld_off` is the offset to the field in the structure and `mode`
* indicates whether cache maintenance need to performed for the write.
* The `data` is the pointer to data of size specified by `size`.
* Returns SDS_OK on success or corresponding error codes on failure.
*/
int sds_struct_write(uint32_t structure_id, unsigned int fld_off,
void *data, size_t size, sds_access_mode_t mode)
{
int status;
uintptr_t field_base;
struct_header_t *header = NULL;
if (!data)
return SDS_ERR_INVALID_PARAMS;
/* Check if a structure with this ID exists */
status = get_struct_header(structure_id, &header);
if (status != SDS_OK)
return status;
assert(header);
if (mode == SDS_ACCESS_MODE_CACHED)
inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
if (!IS_SDS_HEADER_VALID(header)) {
WARN("SDS: Writing to un-finalized structure 0x%x\n",
structure_id);
return SDS_ERR_STRUCT_NOT_FINALIZED;
}
if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
return SDS_ERR_FAIL;
field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
if (check_uptr_overflow(field_base, size - 1))
return SDS_ERR_FAIL;
/* Copy the required field in the struct */
memcpy((void *)field_base, data, size);
if (mode == SDS_ACCESS_MODE_CACHED)
flush_dcache_range((uintptr_t)field_base, size);
return SDS_OK;
}
/*
* Initialize the SDS driver. Also verifies the SDS version and sanity of
* the SDS structure headers.
* Returns SDS_OK on success, SDS_ERR_FAIL on error.
*/
int sds_init(void)
{
sds_mem_base = (uintptr_t)PLAT_ARM_SDS_MEM_BASE;
if (!IS_SDS_REGION_VALID(sds_mem_base)) {
WARN("SDS: No valid SDS Memory Region found\n");
return SDS_ERR_FAIL;
}
if (GET_SDS_REGION_SCHEMA_VERSION(sds_mem_base)
!= SDS_REGION_SCH_VERSION) {
WARN("SDS: Unsupported SDS schema version\n");
return SDS_ERR_FAIL;
}
sds_mem_size = GET_SDS_REGION_SIZE(sds_mem_base);
if (sds_mem_size > PLAT_ARM_SDS_MEM_SIZE_MAX) {
WARN("SDS: SDS Memory Region exceeds size limit\n");
return SDS_ERR_FAIL;
}
INFO("SDS: Detected SDS Memory Region (%zu bytes)\n", sds_mem_size);
if (validate_sds_struct_headers() != SDS_OK)
return SDS_ERR_FAIL;
return SDS_OK;
}
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SDS_H__
#define __SDS_H__
/* SDS Structure Identifier defines */
/* AP CPU INFO defines */
#define SDS_AP_CPU_INFO_STRUCT_ID 1
#define SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET 0x0
#define SDS_AP_CPU_INFO_PRIMARY_CPUID_SIZE 0x4
/* ROM Firmware Version defines */
#define SDS_ROM_VERSION_STRUCT_ID 2
#define SDS_ROM_VERSION_OFFSET 0x0
#define SDS_ROM_VERSION_SIZE 0x4
/* RAM Firmware version defines */
#define SDS_RAM_VERSION_STRUCT_ID 3
#define SDS_RAM_VERSION_OFFSET 0x0
#define SDS_RAM_VERSION_SIZE 0x4
/* Platform Identity defines */
#define SDS_PLATFORM_IDENTITY_STRUCT_ID 4
#define SDS_PLATFORM_IDENTITY_ID_OFFSET 0x0
#define SDS_PLATFORM_IDENTITY_ID_SIZE 0x4
#define SDS_PLATFORM_IDENTITY_ID_CONFIG_SHIFT 28
#define SDS_PLATFORM_IDENTITY_ID_CONFIG_WIDTH 4
#define SDS_PLATFORM_IDENTITY_ID_CONFIG_MASK \
((1 << SDS_PLATFORM_IDENTITY_ID_CONFIG_WIDTH) - 1)
#define SDS_PLATFORM_IDENTITY_PLAT_TYPE_OFFSET 0x4
#define SDS_PLATFORM_IDENTITY_PLAT_TYPE_SIZE 0x4
/* Reset Syndrome defines */
#define SDS_RESET_SYNDROME_STRUCT_ID 5
#define SDS_RESET_SYNDROME_OFFSET 0
#define SDS_RESET_SYNDROME_SIZE 4
#define SDS_RESET_SYNDROME_POW_ON_RESET_BIT (1 << 0)
#define SDS_RESET_SYNDROME_SCP_WD_RESET_BIT (1 << 1)
#define SDS_RESET_SYNDROME_AP_WD_RESET_BIT (1 << 2)
#define SDS_RESET_SYNDROME_SYS_RESET_REQ_BIT (1 << 3)
#define SDS_RESET_SYNDROME_M3_LOCKUP_BIT (1 << 4)
/* SCP Firmware Feature Availability defines */
#define SDS_FEATURE_AVAIL_STRUCT_ID 6
#define SDS_FEATURE_AVAIL_OFFSET 0
#define SDS_FEATURE_AVAIL_SIZE 4
#define SDS_FEATURE_AVAIL_SCP_RAM_READY_BIT (1 << 0)
#define SDS_FEATURE_AVAIL_DMC_READY_BIT (1 << 1)
#define SDS_FEATURE_AVAIL_MSG_IF_READY_BIT (1 << 2)
/* SCP BL2 Image Metadata defines */
#define SDS_SCP_IMG_STRUCT_ID 9
#define SDS_SCP_IMG_FLAG_OFFSET 0
#define SDS_SCP_IMG_FLAG_SIZE 4
#define SDS_SCP_IMG_VALID_FLAG_BIT (1 << 0)
#define SDS_SCP_IMG_ADDR_OFFSET 4
#define SDS_SCP_IMG_ADDR_SIZE 4
#define SDS_SCP_IMG_SIZE_OFFSET 8
#define SDS_SCP_IMG_SIZE_SIZE 4
/* SDS Driver Error Codes */
#define SDS_OK 0
#define SDS_ERR_FAIL -1
#define SDS_ERR_INVALID_PARAMS -2
#define SDS_ERR_STRUCT_NOT_FOUND -3
#define SDS_ERR_STRUCT_NOT_FINALIZED -4
#ifndef __ASSEMBLY__
#include <stddef.h>
#include <stdint.h>
typedef enum {
SDS_ACCESS_MODE_NON_CACHED,
SDS_ACCESS_MODE_CACHED,
} sds_access_mode_t;
int sds_init(void);
int sds_struct_exists(uint32_t structure_id);
int sds_struct_read(uint32_t structure_id, unsigned int fld_off, void *data,
size_t size, sds_access_mode_t mode);
int sds_struct_write(uint32_t structure_id, unsigned int fld_off, void *data,
size_t size, sds_access_mode_t mode);
#endif /*__ASSEMBLY__ */
#endif /* __SDS_H__ */
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __SDS_PRIVATE_H__
#define __SDS_PRIVATE_H__
/* SDS Header defines */
#define SDS_HEADER_ID_SHIFT 0
#define SDS_HEADER_ID_WIDTH 16
#define SDS_HEADER_ID_MASK ((1 << SDS_HEADER_ID_WIDTH) - 1)
#define SDS_HEADER_MINOR_VERSION_WIDTH 8
#define SDS_HEADER_MINOR_VERSION_SHIFT 16
#define SDS_HEADER_MAJOR_VERSION_WIDTH 8
#define MAKE_SDS_HEADER_VERSION(major, minor) \
(((((major) & 0xff) << SDS_HEADER_MINOR_VERSION_WIDTH) | ((minor) & 0xff)))
#define SDS_HEADER_VERSION_MASK \
((1 << (SDS_HEADER_MINOR_VERSION_WIDTH + SDS_HEADER_MAJOR_VERSION_WIDTH)) - 1)
#define SDS_HEADER_VERSION MAKE_SDS_HEADER_VERSION(1, 0)
#define SDS_HEADER_STRUCT_SIZE_WIDTH 23
#define SDS_HEADER_STRUCT_SIZE_SHIFT 1
#define SDS_HEADER_STRUCT_SIZE_MASK ((1 << SDS_HEADER_STRUCT_SIZE_WIDTH) - 1)
#define SDS_HEADER_VALID_MASK 0x1
#define SDS_HEADER_VALID_SHIFT 0
#define SDS_HEADER_SIZE 0x8
/* Arbitrary, 16 bit value that indicates a valid SDS Memory Region */
#define SDS_REGION_SIGNATURE 0xAA7A
#define SDS_REGION_SIGNATURE_WIDTH 16
#define SDS_REGION_SIGNATURE_SHIFT 0
#define SDS_REGION_SIGNATURE_MASK ((1 << SDS_REGION_SIGNATURE_WIDTH) - 1)
#define SDS_REGION_STRUCT_COUNT_SHIFT 16
#define SDS_REGION_STRUCT_COUNT_WIDTH 8
#define SDS_REGION_STRUCT_COUNT_MASK ((1 << SDS_REGION_STRUCT_COUNT_WIDTH) - 1)
#define SDS_REGION_SCH_MINOR_SHIFT 24
#define SDS_REGION_SCH_MINOR_WIDTH 4
#define SDS_REGION_SCH_MINOR_MASK ((1 << SDS_REGION_SCH_MINOR_WIDTH) - 1)
#define SDS_REGION_SCH_MAJOR_SHIFT 28
#define SDS_REGION_SCH_MAJOR_WIDTH 4
#define SDS_REGION_SCH_MAJOR_MASK ((1 << SDS_REGION_SCH_MAJOR_WIDTH) - 1)
#define SDS_REGION_SCH_VERSION_MASK \
((1 << (SDS_REGION_SCH_MINOR_WIDTH + SDS_REGION_SCH_MAJOR_WIDTH)) - 1)
#define MAKE_SDS_REGION_SCH_VERSION(maj, min) \
((((maj) & SDS_REGION_SCH_MAJOR_MASK) << SDS_REGION_SCH_MINOR_WIDTH) | \
((min) & SDS_REGION_SCH_MINOR_MASK))
#define SDS_REGION_SCH_VERSION MAKE_SDS_REGION_SCH_VERSION(1, 0)
#define SDS_REGION_REGIONSIZE_OFFSET 0x4
#define SDS_REGION_DESC_SIZE 0x8
#ifndef __ASSEMBLY__
#include <stddef.h>
#include <stdint.h>
/* Header containing Shared Data Structure metadata */
typedef struct structure_header {
uint32_t reg[2];
} struct_header_t;
#define GET_SDS_HEADER_ID(header) \
((((struct_header_t *)(header))->reg[0]) & SDS_HEADER_ID_MASK)
#define GET_SDS_HEADER_VERSION(header) \
(((((struct_header_t *)(header))->reg[0]) >> SDS_HEADER_MINOR_VERSION_SHIFT)\
& SDS_HEADER_VERSION_MASK)
#define GET_SDS_HEADER_STRUCT_SIZE(header) \
(((((struct_header_t *)(header))->reg[1]) >> SDS_HEADER_STRUCT_SIZE_SHIFT)\
& SDS_HEADER_STRUCT_SIZE_MASK)
#define IS_SDS_HEADER_VALID(header) \
((((struct_header_t *)(header))->reg[1]) & SDS_HEADER_VALID_MASK)
#define GET_SDS_STRUCT_FIELD(header, field_offset) \
((((uint8_t *)(header)) + sizeof(struct_header_t)) + (field_offset))
/* Region Descriptor describing the SDS Memory Region */
typedef struct region_descriptor {
uint32_t reg[2];
} region_desc_t;
#define IS_SDS_REGION_VALID(region) \
(((((region_desc_t *)(region))->reg[0]) & SDS_REGION_SIGNATURE_MASK) == SDS_REGION_SIGNATURE)
#define GET_SDS_REGION_STRUCTURE_COUNT(region) \
(((((region_desc_t *)(region))->reg[0]) >> SDS_REGION_STRUCT_COUNT_SHIFT)\
& SDS_REGION_STRUCT_COUNT_MASK)
#define GET_SDS_REGION_SCHEMA_VERSION(region) \
(((((region_desc_t *)(region))->reg[0]) >> SDS_REGION_SCH_MINOR_SHIFT)\
& SDS_REGION_SCH_VERSION_MASK)
#define GET_SDS_REGION_SIZE(region) ((((region_desc_t *)(region))->reg[1]))
#endif /* __ASSEMBLY__ */
#endif /* __SDS_PRIVATE_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment