Merge changes from topic "imx8ulp_support" into integration

* changes:
  docs(maintainers): add the maintainers for imx8ulp
  docs(imx8ulp): add imx8ulp platform
  fix(imx8ulp): increase the mmap region num
  feat(imx8ulp): adjust the dram mapped region
  feat(imx8ulp): ddrc switch auto low power and software interface
  feat(imx8ulp): add some delay before cmc1 access
  feat(imx8ulp): add a flag check for the ddr status
  fix(imx8ulp): add sw workaround for csi/hotplug test hang
  feat(imx8ulp): adjust the voltage when sys dvfs enabled
  feat(imx8ulp): enable the DDR frequency scaling support
  fix(imx8ulp): fix suspend/resume issue when DBD owner is s400 only
  feat(imx8ulp): update XRDC for ELE to access DDR with CA35 DID
  feat(imx8ulp): add memory region policy
  feat(imx8ulp): protect TEE region for secure access only
  feat(imx8ulp): add trusty support
  feat(imx8ulp): add OPTEE support
  feat(imx8ulp): update the upower config for power optimization
  feat(imx8ulp): allow RTD to reset APD through MU
  feat(imx8ulp): not power off LPAV PD when LPAV owner is RTD
  feat(imx8ulp): add system power off support
  feat(imx8ulp): add APD power down mode(PD) support in system suspend
  feat(imx8ulp): add the basic support for idle & system suspned
  feat(imx8ulp): enable 512KB cache after resume on imx8ulp
  feat(imx8ulp): add the initial XRDC support
  feat(imx8ulp): allocated caam did for the non secure world
  feat(imx8ulp): add i.MX8ULP basic support
  build(changelog): add new scopes for nxp imx8ulp platform
  feat(scmi): add scmi sensor support
This commit is contained in:
Manish Pandey 2024-03-01 12:37:14 +01:00 committed by TrustedFirmware Code Review
commit 1c408d3c40
37 changed files with 11442 additions and 4 deletions

View file

@ -413,6 +413,9 @@ subsections:
- title: i.MX 8
scope: imx8
- title: i.MX 8ULP
scope: imx8ulp
- title: i.MX 9
scope: imx9

View file

@ -646,6 +646,13 @@ NXP i.MX8M platform port
:|F|: docs/plat/imx8m.rst
:|F|: plat/imx/imx8m/
NXP i.MX8ULP platform port
^^^^^^^^^^^^^^^^^^^^^^^^^^
:|M|: Jacky Bai <ping.bai@nxp.com>
:|G|: `JackyBai`_
:|F|: docs/plat/imx8ulp.rst
:|F|: plat/imx/imx8ulp/
NXP i.MX9 platform port
^^^^^^^^^^^^^^^^^^^^^^^^
:|M|: Jacky Bai <ping.bai@nxp.com>

69
docs/plat/imx8ulp.rst Normal file
View file

@ -0,0 +1,69 @@
NXP i.MX 8ULP
==================
i.MX 8ULP is part of the ULP family with emphasis on extreme low-power techniques
using the 28 nm fully depleted silicon on insulator process. Like i.MX 7ULP,
i.MX 8ULP continues to be based on asymmetric architecture.
The i.MX 8ULP family of processors features NXPs advanced implementation of the
dual Arm Cortex-A35 cores alongside an Arm Cortex-M33. This combined architecture
enables the device to run a rich operating system (such as Linux) on the Cortex-A35
core and an RTOS (such as FreeRTOS) on the Cortex-M33 core. It also includes a Cadence
Tensilica Fusion DSP for low-power audio and a HiFi4 DSP for advanced audio and machine
learning applications.
The design enables clean separation between two processing domains, where each has
separate power, clocking and peripheral islands, but the bus fabric of each domain
is tightly integrated for efficient communication. The part is streamlined to minimize
pin count, enabling small packages and simple system integration. This microprocessor
is intended for applications where efficiency and simple system integration is important.
`i.MX8ULP Applications Processors`_.
Boot Sequence
-------------
BootROM --> SPL --> BL31 --> BL33(u-boot) --> Linux kernel
How to build
------------
Build Procedure
~~~~~~~~~~~~~~~
- Prepare AARCH64 toolchain.
- Get the ELE FW image from NXP linux SDK package
- Build SPL and u-boot firstly, and get binary images: u-boot-spl.bin,
u-boot.bin and dtb
- Build TF-A
Build bl31:
.. code:: shell
CROSS_COMPILE=aarch64-linux-gnu- make PLAT=<Target_SoC> bl31
Target_SoC should be "imx8ulp" for i.MX8ULP SoC.
Deploy TF-A Images
~~~~~~~~~~~~~~~~~~
TF-A binary(bl31.bin), u-boot-spl.bin u-boot.bin, ELE FW image are combined
together to generate a binary file called flash.bin, the imx-mkimage tool is
used to generate flash.bin, and flash.bin needs to be flashed into SD card
with certain offset for BOOT ROM.
Reference Documentation
~~~~~~~~~~~~~~~~~~~~~~~
Details on how to prepare, generate & deploy the boot image be found in following documents:
- i.MX Linux User's Guide
`link <https://www.nxp.com/design/software/embedded-software/i-mx-software/embedded-linux-for-i-mx-applications-processors:IMXLINUX>`__
- i.MX Linux Reference Manual
`link <https://www.nxp.com/design/software/embedded-software/i-mx-software/embedded-linux-for-i-mx-applications-processors:IMXLINUX>`__
.. _i.MX8ULP Applications Processors: https://www.nxp.com/products/processors-and-microcontrollers/arm-processors/i-mx-applications-processors/i-mx-8-applications-processors/i-mx-8ulp-applications-processor-family:i.MX8ULP

View file

@ -27,6 +27,7 @@ Platform Ports
warp7
imx8
imx8m
imx8ulp
imx9
npcm845x
nxp/index

View file

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2020, Linaro Limited
*/
#ifndef SCMI_MSG_COMMON_H
@ -15,6 +15,7 @@
#include "clock.h"
#include "power_domain.h"
#include "reset_domain.h"
#include "sensor.h"
#define SCMI_VERSION 0x20000U
#define SCMI_IMPL_VERSION 0U
@ -118,6 +119,13 @@ scmi_msg_handler_t scmi_msg_get_rstd_handler(struct scmi_msg *msg);
*/
scmi_msg_handler_t scmi_msg_get_pd_handler(struct scmi_msg *msg);
/*
* scmi_msg_get_sensor_handler - Return a handler for a sensor message
* @msg - message to process
* Return a function handler for the message or NULL
*/
scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg);
/*
* Process Read, process and write response for input SCMI message
*

View file

@ -15,6 +15,7 @@
#pragma weak scmi_msg_get_rstd_handler
#pragma weak scmi_msg_get_pd_handler
#pragma weak scmi_msg_get_voltage_handler
#pragma weak scmi_msg_get_sensor_handler
scmi_msg_handler_t scmi_msg_get_clock_handler(struct scmi_msg *msg __unused)
{
@ -36,6 +37,11 @@ scmi_msg_handler_t scmi_msg_get_voltage_handler(struct scmi_msg *msg __unused)
return NULL;
}
scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg __unused)
{
return NULL;
}
void scmi_status_response(struct scmi_msg *msg, int32_t status)
{
assert(msg->out && msg->out_size >= sizeof(int32_t));
@ -75,6 +81,9 @@ void scmi_process_message(struct scmi_msg *msg)
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
handler = scmi_msg_get_pd_handler(msg);
break;
case SCMI_PROTOCOL_ID_SENSOR:
handler = scmi_msg_get_sensor_handler(msg);
break;
default:
break;
}

277
drivers/scmi-msg/sensor.c Normal file
View file

@ -0,0 +1,277 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright 2021-2024 NXP
*/
#include <cdefs.h>
#include <string.h>
#include "common.h"
#include <drivers/scmi-msg.h>
#include <drivers/scmi.h>
#include <lib/utils_def.h>
static bool message_id_is_supported(size_t message_id);
uint16_t plat_scmi_sensor_count(unsigned int agent_id __unused)
{
if (sensor_ops.sensor_count != NULL) {
return sensor_ops.sensor_count(agent_id);
}
return 0U;
}
uint8_t plat_scmi_sensor_max_requests(unsigned int agent_id __unused)
{
if (sensor_ops.sensor_max_request != NULL) {
return sensor_ops.sensor_max_request(agent_id);
}
return 0U;
}
uint32_t plat_scmi_sensor_reg(unsigned int agent_id __unused,
unsigned int *addr)
{
if (sensor_ops.get_sensor_req != NULL) {
return sensor_ops.get_sensor_req(agent_id, addr);
}
return 0U;
}
int32_t plat_scmi_sensor_reading_get(uint32_t agent_id __unused,
uint16_t sensor_id __unused,
uint32_t *val __unused)
{
if (sensor_ops.sensor_reading_get != NULL) {
return sensor_ops.sensor_reading_get(agent_id, sensor_id, val);
}
return 0;
}
uint32_t plat_scmi_sensor_description_get(uint32_t agent_id __unused,
uint16_t desc_index __unused,
struct scmi_sensor_desc *desc __unused)
{
if (sensor_ops.sensor_description_get != NULL) {
return sensor_ops.sensor_description_get(agent_id, desc_index, desc);
}
return 0U;
}
uint32_t plat_scmi_sensor_update_interval(uint32_t agent_id __unused,
uint16_t sensor_id __unused)
{
if (sensor_ops.sensor_update_interval != NULL) {
return sensor_ops.sensor_update_interval(agent_id, sensor_id);
}
return 0U;
}
uint32_t plat_scmi_sensor_state(uint32_t agent_id __unused,
uint16_t sensor_id __unused)
{
if (sensor_ops.sensor_state != NULL) {
return sensor_ops.sensor_state(agent_id, sensor_id);
}
return 0U;
}
uint32_t plat_scmi_sensor_timestamped(uint32_t agent_id __unused,
uint16_t sensor_id __unused)
{
if (sensor_ops.sensor_timestamped != NULL) {
return sensor_ops.sensor_timestamped(agent_id, sensor_id);
}
return 0U;
}
static void report_version(struct scmi_msg *msg)
{
struct scmi_protocol_version_p2a return_values = {
.status = SCMI_SUCCESS,
.version = SCMI_PROTOCOL_VERSION_SENSOR,
};
if (msg->in_size != 0U) {
scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
return;
}
scmi_write_response(msg, &return_values, sizeof(return_values));
}
static void report_attributes(struct scmi_msg *msg)
{
unsigned int addr[2];
unsigned int len;
struct scmi_protocol_attributes_p2a_sensor return_values = {
.status = SCMI_SUCCESS,
};
if (msg->in_size != 0U) {
scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
return;
}
return_values.num_sensors = plat_scmi_sensor_count(msg->agent_id);
return_values.max_reqs = plat_scmi_sensor_max_requests(msg->agent_id);
len = plat_scmi_sensor_reg(msg->agent_id, addr);
if (len != 0U) {
return_values.sensor_reg_low = addr[0];
return_values.sensor_reg_high = addr[1];
return_values.sensor_reg_len = len;
}
scmi_write_response(msg, &return_values, sizeof(return_values));
}
static void report_message_attributes(struct scmi_msg *msg)
{
struct scmi_protocol_message_attributes_a2p *in_args = (void *)msg->in;
struct scmi_protocol_message_attributes_p2a return_values = {
.status = SCMI_SUCCESS,
/* For this protocol, attributes shall be zero */
.attributes = 0U,
};
if (msg->in_size != sizeof(*in_args)) {
scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
return;
}
if (!message_id_is_supported(in_args->message_id)) {
scmi_status_response(msg, SCMI_NOT_FOUND);
return;
}
scmi_write_response(msg, &return_values, sizeof(return_values));
}
static void scmi_sensor_description_get(struct scmi_msg *msg)
{
const struct scmi_sensor_description_get_a2p *in_args = (void *)msg->in;
struct scmi_sensor_description_get_p2a return_values = {
.status = SCMI_SUCCESS,
};
struct scmi_sensor_desc desc;
unsigned int desc_index = 0U;
unsigned int num_sensor_flags;
if (msg->in_size != sizeof(*in_args)) {
scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
return;
}
desc_index = SPECULATION_SAFE_VALUE(in_args->desc_index);
num_sensor_flags = plat_scmi_sensor_description_get(msg->agent_id, desc_index,
&desc);
return_values.num_sensor_flags = num_sensor_flags;
memcpy(msg->out, &return_values, sizeof(return_values));
memcpy(msg->out + sizeof(return_values), &desc, sizeof(desc));
msg->out_size_out = sizeof(return_values) + sizeof(struct scmi_sensor_desc);
}
static void scmi_sensor_config_get(struct scmi_msg *msg)
{
const struct scmi_sensor_config_get_a2p *in_args = (void *)msg->in;
struct scmi_sensor_config_get_p2a return_values = {
.status = SCMI_SUCCESS,
};
unsigned int sensor_id = 0U;
uint32_t update_interval, state, timestamped;
if (msg->in_size != sizeof(*in_args)) {
scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
return;
}
sensor_id = SPECULATION_SAFE_VALUE(in_args->sensor_id);
if (sensor_id >= plat_scmi_sensor_count(msg->agent_id)) {
scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
return;
}
update_interval = plat_scmi_sensor_update_interval(msg->agent_id, sensor_id);
state = plat_scmi_sensor_state(msg->agent_id, sensor_id);
timestamped = plat_scmi_sensor_timestamped(msg->agent_id, sensor_id);
return_values.sensor_config = (update_interval << 11) | (timestamped << 1) | state;
scmi_write_response(msg, &return_values, sizeof(return_values));
}
static void scmi_sensor_reading_get(struct scmi_msg *msg)
{
const struct scmi_sensor_reading_get_a2p *in_args = (void *)msg->in;
struct scmi_sensor_reading_get_p2a return_values = {
.status = SCMI_SUCCESS,
};
unsigned int sensor_id = 0U;
int32_t ret;
if (msg->in_size != sizeof(*in_args)) {
scmi_status_response(msg, SCMI_PROTOCOL_ERROR);
return;
}
sensor_id = SPECULATION_SAFE_VALUE(in_args->sensor_id);
if (sensor_id >= plat_scmi_sensor_count(msg->agent_id)) {
scmi_status_response(msg, SCMI_INVALID_PARAMETERS);
return;
}
ret = plat_scmi_sensor_reading_get(msg->agent_id, sensor_id,
(uint32_t *)&return_values.val);
if (ret) {
scmi_status_response(msg, SCMI_HARDWARE_ERROR);
return;
}
scmi_write_response(msg, &return_values, sizeof(return_values));
}
static void scmi_sensor_list_update_intervals(struct scmi_msg *msg)
{
/* TODO */
scmi_status_response(msg, SCMI_NOT_SUPPORTED);
}
static const scmi_msg_handler_t scmi_sensor_handler_table[SCMI_SENSOR_MAX] = {
[SCMI_PROTOCOL_VERSION] = report_version,
[SCMI_PROTOCOL_ATTRIBUTES] = report_attributes,
[SCMI_PROTOCOL_MESSAGE_ATTRIBUTES] = report_message_attributes,
[SCMI_SENSOR_DESCRIPTION_GET] = scmi_sensor_description_get,
[SCMI_SENSOR_CONFIG_GET] = scmi_sensor_config_get,
[SCMI_SENSOR_LIST_UPDATE_INTERVALS] = scmi_sensor_list_update_intervals,
[SCMI_SENSOR_READING_GET] = scmi_sensor_reading_get,
};
static bool message_id_is_supported(size_t message_id)
{
return scmi_sensor_handler_table[message_id] != NULL;
}
scmi_msg_handler_t scmi_msg_get_sensor_handler(struct scmi_msg *msg)
{
unsigned int message_id = SPECULATION_SAFE_VALUE(msg->message_id);
if (!message_id_is_supported(message_id)) {
VERBOSE("pd handle not found %u\n", msg->message_id);
return NULL;
}
return scmi_sensor_handler_table[message_id];
}

125
drivers/scmi-msg/sensor.h Normal file
View file

@ -0,0 +1,125 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright 2023-2024 NXP
*/
#ifndef SCMI_MSG_SENSOR_H
#define SCMI_MSG_SENSOR_H
#include <stdint.h>
#include <lib/utils_def.h>
#define SCMI_PROTOCOL_VERSION_SENSOR 0x20000U
/*
* Identifiers of the SCMI SENSOR Protocol commands
*/
enum scmi_sensor_command_id {
SCMI_SENSOR_DESCRIPTION_GET = 0x003,
SCMI_SENSOR_TRIP_POINT_NOTIFY = 0x004,
SCMI_SENSOR_TRIP_POINT_CONFIG = 0x005,
SCMI_SENSOR_READING_GET = 0x006,
SCMI_SENSOR_AXIS_DESCRIPTION_GET = 0x007,
SCMI_SENSOR_LIST_UPDATE_INTERVALS = 0x008,
SCMI_SENSOR_CONFIG_GET = 0x009,
SCMI_SENSOR_CONFIG_SET = 0x00A,
SCMI_SENSOR_CONTINUOUS_UPDATE_NOTIFY = 0x00B,
SCMI_SENSOR_MAX = 0x00C,
};
/* Protocol attributes */
struct scmi_protocol_attributes_p2a_sensor {
int32_t status;
int16_t num_sensors;
uint8_t max_reqs;
uint8_t res;
uint32_t sensor_reg_low;
uint32_t sensor_reg_high;
uint32_t sensor_reg_len;
};
#define SCMI_SENSOR_NAME_LENGTH_MAX 16U
struct scmi_sensor_desc {
uint32_t id;
uint32_t attr_low;
uint32_t attr_high;
uint8_t name[SCMI_SENSOR_NAME_LENGTH_MAX];
uint32_t power;
uint32_t resolution;
int32_t min_range_low;
int32_t min_range_high;
int32_t max_range_low;
int32_t max_range_high;
};
struct scmi_sensor_description_get_a2p {
uint32_t desc_index;
};
struct scmi_sensor_description_get_p2a {
int32_t status;
uint32_t num_sensor_flags;
};
struct scmi_sensor_config_get_a2p {
uint32_t sensor_id;
};
struct scmi_sensor_config_get_p2a {
int32_t status;
uint32_t sensor_config;
};
/*
* Sensor Reading Get
*/
struct scmi_sensor_reading_get_a2p {
uint32_t sensor_id;
uint32_t flags;
};
struct scmi_sensor_val {
uint32_t value_low;
uint32_t value_high;
uint32_t timestap_low;
uint32_t timestap_high;
};
struct scmi_sensor_reading_get_p2a {
int32_t status;
struct scmi_sensor_val val;
};
typedef struct {
uint16_t (*sensor_count)(unsigned int agent_id);
uint8_t (*sensor_max_request)(unsigned int agent_id);
uint32_t (*get_sensor_req)(unsigned int agent_id, unsigned int *addr);
int32_t (*sensor_reading_get)(uint32_t agent_id, uint16_t sensor_id,
uint32_t *val);
uint32_t (*sensor_description_get)(unsigned int agent_id, uint16_t sensor_id,
struct scmi_sensor_desc *desc);
uint32_t (*sensor_update_interval)(uint32_t agent_id, uint16_t sensor_id);
uint32_t (*sensor_state)(uint32_t agent_id, uint16_t sensor_id);
uint16_t (*sensor_timestamped)(uint32_t agent_id, uint16_t sensor_id);
} plat_scmi_sensor_ops_t;
#define REGISTER_SCMI_SENSOR_OPS(_sensor_count, _sensor_max_request, \
_get_sensor_req, _sensor_reading_get, \
_sensor_description_get, _sensor_update_interval, \
_sensor_state, _sensor_timestamped) \
const plat_scmi_sensor_ops_t sensor_ops = { \
.sensor_count = _sensor_count, \
.sensor_max_request = _sensor_max_request, \
.get_sensor_req = _get_sensor_req, \
.sensor_reading_get = _sensor_reading_get, \
.sensor_description_get = _sensor_description_get, \
.sensor_update_interval = _sensor_update_interval, \
.sensor_state = _sensor_state, \
.sensor_timestamped = _sensor_timestamped, \
}
extern const plat_scmi_sensor_ops_t sensor_ops;
#endif /* SCMI_MSG_SENSOR_H */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2015-2024, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -86,6 +86,51 @@ func plat_calc_core_pos
ret
endfunc plat_calc_core_pos
/* ----------------------------------------------
* function to handle platform specific reset.
* ----------------------------------------------
*/
func plat_reset_handler
#if defined(PLAT_imx8ulp)
/* enable the 512KB cache by default */
mov x0, #IMX_SIM1_BASE
/*
* if the RVBADDR is ROM entry, that means we did
* NOT switch the L2 cache to 512KB. default is 256K config,
* so skip
*/
ldr w1, [x0, #0x5c]
cmp w1, #0x1000
b.eq 1f
add x0, x0, #0x30
ldr w1, [x0]
/* if already 512KB config, skip */
tbnz w1, #4, 1f
ldr w1, [x0]
orr w1, w1, #0x10
str w1, [x0]
orr w1, w1, #0x10000
str w1, [x0]
b .
1: mrs x0, CORTEX_A35_CPUECTLR_EL1
orr x0, x0, #(0x1 << 0)
orr x0, x0, #(0x1 << 3)
msr CORTEX_A35_CPUECTLR_EL1, x0
mrs x0, CORTEX_A35_L2ECTLR_EL1
orr x0, x0, #(0x1 << 0)
msr CORTEX_A35_L2ECTLR_EL1, x0
isb
#endif
/* enable EL2 cpuectlr RW access */
mov x0, #0x73
msr actlr_el3, x0
msr actlr_el2, x0
isb
ret
endfunc plat_reset_handler
/* ---------------------------------------------
* function to get the entrypoint.
* ---------------------------------------------

View file

@ -0,0 +1,23 @@
/*
* Copyright 2023-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <imx_plat_common.h>
uint32_t plat_get_spsr_for_bl33_entry(void)
{
unsigned long el_status;
unsigned long mode;
uint32_t spsr;
/* figure out what mode we enter the non-secure world */
el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
el_status &= ID_AA64PFR0_ELX_MASK;
mode = (el_status) ? MODE_EL2 : MODE_EL1;
spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
return spsr;
}

View file

@ -332,3 +332,16 @@ int imx_kernel_entry_handler(uint32_t smc_fid,
return 0;
}
#if defined(PLAT_imx8ulp)
int imx_hifi_xrdc(uint32_t smc_fid)
{
mmio_setbits_32(IMX_SIM2_BASE + 0x8, BIT_32(19) | BIT_32(17) | BIT_32(18));
mmio_clrbits_32(IMX_SIM2_BASE + 0x8, BIT_32(16));
extern int xrdc_apply_hifi_config(void);
xrdc_apply_hifi_config();
return 0;
}
#endif

View file

@ -1,14 +1,17 @@
/*
* Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2015-2024, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <drivers/scmi-msg.h>
#include <lib/pmf/pmf.h>
#include <tools_share/uuid.h>
#include <imx_sip_svc.h>
static int32_t imx_sip_setup(void)
@ -29,6 +32,17 @@ static uintptr_t imx_sip_handler(unsigned int smc_fid,
case IMX_SIP_AARCH32:
SMC_RET1(handle, imx_kernel_entry_handler(smc_fid, x1, x2, x3, x4));
break;
#if defined(PLAT_imx8ulp)
case IMX_SIP_SCMI:
scmi_smt_fastcall_smc_entry(0);
SMC_RET1(handle, 0);
break;
case IMX_SIP_HIFI_XRDC:
SMC_RET1(handle, imx_hifi_xrdc(smc_fid));
break;
case IMX_SIP_DDR_DVFS:
return dram_dvfs_handler(smc_fid, handle, x1, x2, x3);
#endif
#if defined(PLAT_imx8mq)
case IMX_SIP_GET_SOC_INFO:
SMC_RET1(handle, imx_soc_info_handler(smc_fid, x1, x2, x3));

View file

@ -0,0 +1,16 @@
/*
* Copyright 2023-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IMX_PLAT_COMMON_H
#define IMX_PLAT_COMMON_H
#include <stdint.h>
#include <arch_helpers.h>
uint32_t plat_get_spsr_for_bl33_entry(void);
#endif /*IMX_PLAT_COMMON_H */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2023, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2015-2024, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -52,6 +52,11 @@
int imx_kernel_entry_handler(uint32_t smc_fid, u_register_t x1,
u_register_t x2, u_register_t x3,
u_register_t x4);
#define IMX_SIP_SCMI 0xC20000FE
#define IMX_SIP_HIFI_XRDC 0xC200000E
#if defined(PLAT_imx8mq)
int imx_soc_info_handler(uint32_t smc_fid, u_register_t x1,
u_register_t x2, u_register_t x3);
@ -96,5 +101,12 @@ int imx_misc_set_temp_handler(uint32_t smc_fid, u_register_t x1,
uint64_t imx_buildinfo_handler(uint32_t smc_fid, u_register_t x1,
u_register_t x2, u_register_t x3,
u_register_t x4);
int scmi_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3);
int imx_hifi_xrdc(uint32_t smc_fid);
#if defined(PLAT_imx8ulp)
int dram_dvfs_handler(uint32_t smc_fid, void *handle,
u_register_t x1, u_register_t x2, u_register_t x3);
#endif
#endif /* __IMX_SIP_SVC_H__ */

View file

@ -0,0 +1,657 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdbool.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <plat_imx8.h>
#include <xrdc.h>
#define PCC_PR BIT(31)
#define PFD_VALID_MASK U(0x40404040)
#define S400_MU_BASE U(0x27020000)
#define S400_MU_RSR (S400_MU_BASE + 0x12c)
#define S400_MU_TRx(i) (S400_MU_BASE + 0x200 + (i) * 4)
#define S400_MU_RRx(i) (S400_MU_BASE + 0x280 + (i) * 4)
/*
* need to re-init the PLL, CGC1, PCC, CMC, XRDC, SIM, GPIO etc.
* init the PLL &PFD first, then switch the CA35 clock to PLL for
* performance consideration, restore other bus fabric clock.
*/
extern void imx8ulp_caam_init(void);
extern void upower_wait_resp(void);
extern void dram_enter_retention(void);
extern void dram_exit_retention(void);
struct plat_gic_ctx imx_gicv3_ctx;
static uint32_t cmc1_pmprot;
static uint32_t cmc1_srie;
/* TPM5: global timer */
static uint32_t tpm5[3];
static uint32_t wdog3[2];
/* CGC1 PLL2 */
uint32_t pll2[][2] = {
{0x292c0510, 0x0}, {0x292c0518, 0x0}, {0x292c051c, 0x0},
{0x292c0520, 0x0}, {0x292c0500, 0x0},
};
/* CGC1 PLL3 */
uint32_t pll3[][2] = {
{0x292c0604, 0x0}, {0x292c0608, 0x0}, {0x292c060c, 0x0},
{0x292c0610, 0x0}, {0x292c0618, 0x0}, {0x292c061c, 0x0},
{0x292c0620, 0x0}, {0x292c0624, 0x0}, {0x292c0600, 0x0},
{0x292c0614, 0x0},
};
/* CGC1 others */
uint32_t cgc1[][2] = {
{0x292c0014, 0x0}, {0x292c0034, 0x0}, {0x292c0038, 0x0},
{0x292c0108, 0x0}, {0x292c0208, 0x0}, {0x292c0700, 0x0},
{0x292c0810, 0x0}, {0x292c0900, 0x0}, {0x292c0904, 0x0},
{0x292c0908, 0x0}, {0x292c090c, 0x0}, {0x292c0a00, 0x0},
};
static uint32_t pcc3[61];
static uint32_t pcc4[32];
static uint32_t pcc5_0[33];
static uint32_t pcc5_1[][2] = {
{0x2da70084, 0x0}, {0x2da70088, 0x0}, {0x2da7008c, 0x0},
{0x2da700a0, 0x0}, {0x2da700a4, 0x0}, {0x2da700a8, 0x0},
{0x2da700ac, 0x0}, {0x2da700b0, 0x0}, {0x2da700b4, 0x0},
{0x2da700bc, 0x0}, {0x2da700c0, 0x0}, {0x2da700c8, 0x0},
{0x2da700cc, 0x0}, {0x2da700d0, 0x0}, {0x2da700f0, 0x0},
{0x2da700f4, 0x0}, {0x2da700f8, 0x0}, {0x2da70108, 0x0},
{0x2da7010c, 0x0}, {0x2da70110, 0x0}, {0x2da70114, 0x0},
};
static uint32_t cgc2[][2] = {
{0x2da60014, 0x0}, {0x2da60020, 0x0}, {0x2da6003c, 0x0},
{0x2da60040, 0x0}, {0x2da60108, 0x0}, {0x2da60208, 0x0},
{0x2da60900, 0x0}, {0x2da60904, 0x0}, {0x2da60908, 0x0},
{0x2da60910, 0x0}, {0x2da60a00, 0x0},
};
static uint32_t pll4[][2] = {
{0x2da60604, 0x0}, {0x2da60608, 0x0}, {0x2da6060c, 0x0},
{0x2da60610, 0x0}, {0x2da60618, 0x0}, {0x2da6061c, 0x0},
{0x2da60620, 0x0}, {0x2da60624, 0x0}, {0x2da60600, 0x0},
{0x2da60614, 0x0},
};
static uint32_t lpav_sim[][2] = {
{0x2da50000, 0x0}, {0x2da50004, 0x0}, {0x2da50008, 0x0},
{0x2da5001c, 0x0}, {0x2da50020, 0x0}, {0x2da50024, 0x0},
{0x2da50034, 0x0},
};
#define APD_GPIO_CTRL_NUM 2
#define LPAV_GPIO_CTRL_NUM 1
#define GPIO_CTRL_REG_NUM 8
#define GPIO_PIN_MAX_NUM 32
#define GPIO_CTX(addr, num) \
{.base = (addr), .pin_num = (num), }
struct gpio_ctx {
/* gpio base */
uintptr_t base;
/* port control */
uint32_t port_ctrl[GPIO_CTRL_REG_NUM];
/* GPIO ICR, Max 32 */
uint32_t pin_num;
uint32_t gpio_icr[GPIO_PIN_MAX_NUM];
};
static uint32_t gpio_ctrl_offset[GPIO_CTRL_REG_NUM] = {
0xc, 0x10, 0x14, 0x18, 0x1c, 0x40, 0x54, 0x58
};
static struct gpio_ctx apd_gpio_ctx[APD_GPIO_CTRL_NUM] = {
GPIO_CTX(IMX_GPIOE_BASE, 24),
GPIO_CTX(IMX_GPIOF_BASE, 32),
};
static struct gpio_ctx lpav_gpio_ctx = GPIO_CTX(IMX_GPIOD_BASE, 24);
/* iomuxc setting */
#define IOMUXC_SECTION_NUM 8
struct iomuxc_section {
uint32_t offset;
uint32_t reg_num;
};
struct iomuxc_section iomuxc_sections[IOMUXC_SECTION_NUM] = {
{.offset = IOMUXC_PTD_PCR_BASE, .reg_num = 24},
{.offset = IOMUXC_PTE_PCR_BASE, .reg_num = 24},
{.offset = IOMUXC_PTF_PCR_BASE, .reg_num = 32},
{.offset = IOMUXC_PSMI_BASE0, .reg_num = 10},
{.offset = IOMUXC_PSMI_BASE1, .reg_num = 61},
{.offset = IOMUXC_PSMI_BASE2, .reg_num = 12},
{.offset = IOMUXC_PSMI_BASE3, .reg_num = 20},
{.offset = IOMUXC_PSMI_BASE4, .reg_num = 75},
};
static uint32_t iomuxc_ctx[258];
#define PORTS_NUM 3U
void apd_io_pad_off(void)
{
unsigned int i, j;
/* off the PTD/E/F, need to be customized based on actual user case */
for (i = 0; i < PORTS_NUM; i++) {
for (j = 0; j < iomuxc_sections[i].reg_num; j++) {
mmio_write_32(iomuxc_sections[i].offset + j * 4, 0);
}
}
/* disable the PTD compensation */
mmio_write_32(IMX_SIM1_BASE + 0x48, 0x800);
}
void iomuxc_save(void)
{
unsigned int i, j;
unsigned int index = 0U;
for (i = 0U; i < IOMUXC_SECTION_NUM; i++) {
for (j = 0U; j < iomuxc_sections[i].reg_num; j++) {
iomuxc_ctx[index++] = mmio_read_32(iomuxc_sections[i].offset + j * 4);
}
}
apd_io_pad_off();
}
void iomuxc_restore(void)
{
unsigned int i, j;
unsigned int index = 0U;
for (i = 0U; i < IOMUXC_SECTION_NUM; i++) {
for (j = 0U; j < iomuxc_sections[i].reg_num; j++) {
mmio_write_32(iomuxc_sections[i].offset + j * 4, iomuxc_ctx[index++]);
}
}
}
void gpio_save(struct gpio_ctx *ctx, int port_num)
{
unsigned int i, j;
for (i = 0U; i < port_num; i++) {
/* save the port control setting */
for (j = 0U; j < GPIO_CTRL_REG_NUM; j++) {
if (j < 4U) {
ctx->port_ctrl[j] = mmio_read_32(ctx->base + gpio_ctrl_offset[j]);
/*
* clear the permission setting to read the GPIO
* non-secure world setting.
*/
mmio_write_32(ctx->base + gpio_ctrl_offset[j], 0x0);
} else {
ctx->port_ctrl[j] = mmio_read_32(ctx->base + gpio_ctrl_offset[j]);
}
}
/* save the gpio icr setting */
for (j = 0U; j < ctx->pin_num; j++) {
ctx->gpio_icr[j] = mmio_read_32(ctx->base + 0x80 + j * 4);
}
ctx++;
}
}
void gpio_restore(struct gpio_ctx *ctx, int port_num)
{
unsigned int i, j;
for (i = 0U; i < port_num; i++) {
for (j = 0U; j < ctx->pin_num; j++)
mmio_write_32(ctx->base + 0x80 + j * 4, ctx->gpio_icr[j]);
for (j = 4U; j < GPIO_CTRL_REG_NUM; j++) {
mmio_write_32(ctx->base + gpio_ctrl_offset[j], ctx->port_ctrl[j]);
}
/* permission config retore last */
for (j = 0U; j < 4; j++) {
mmio_write_32(ctx->base + gpio_ctrl_offset[j], ctx->port_ctrl[j]);
}
ctx++;
}
}
void cgc1_save(void)
{
unsigned int i;
/* PLL2 */
for (i = 0U; i < ARRAY_SIZE(pll2); i++) {
pll2[i][1] = mmio_read_32(pll2[i][0]);
}
/* PLL3 */
for (i = 0U; i < ARRAY_SIZE(pll3); i++) {
pll3[i][1] = mmio_read_32(pll3[i][0]);
}
/* CGC1 others */
for (i = 0U; i < ARRAY_SIZE(cgc1); i++) {
cgc1[i][1] = mmio_read_32(cgc1[i][0]);
}
}
void cgc1_restore(void)
{
unsigned int i;
/* PLL2 */
for (i = 0U; i < ARRAY_SIZE(pll2); i++) {
mmio_write_32(pll2[i][0], pll2[i][1]);
}
/* wait for PLL2 lock */
while (!(mmio_read_32(pll2[4][0]) & BIT(24))) {
;
}
/* PLL3 */
for (i = 0U; i < 9U; i++) {
mmio_write_32(pll3[i][0], pll3[i][1]);
}
/* wait for PLL3 lock */
while (!(mmio_read_32(pll3[4][0]) & BIT(24))) {
;
}
/* restore the PFDs */
mmio_write_32(pll3[9][0], pll3[9][1] & ~(BIT(31) | BIT(23) | BIT(15) | BIT(7)));
mmio_write_32(pll3[9][0], pll3[9][1]);
/* wait for the PFD is stable, only need to check the enabled PFDs */
while (!(mmio_read_32(pll3[9][0]) & PFD_VALID_MASK)) {
;
}
/* CGC1 others */
for (i = 0U; i < ARRAY_SIZE(cgc1); i++) {
mmio_write_32(cgc1[i][0], cgc1[i][1]);
}
}
void tpm5_save(void)
{
tpm5[0] = mmio_read_32(IMX_TPM5_BASE + 0x10);
tpm5[1] = mmio_read_32(IMX_TPM5_BASE + 0x18);
tpm5[2] = mmio_read_32(IMX_TPM5_BASE + 0x20);
}
void tpm5_restore(void)
{
mmio_write_32(IMX_TPM5_BASE + 0x10, tpm5[0]);
mmio_write_32(IMX_TPM5_BASE + 0x18, tpm5[1]);
mmio_write_32(IMX_TPM5_BASE + 0x20, tpm5[2]);
}
void wdog3_save(void)
{
/* enable wdog3 clock */
mmio_write_32(IMX_PCC3_BASE + 0xa8, 0xd2800000);
/* save the CS & TOVAL regiter */
wdog3[0] = mmio_read_32(IMX_WDOG3_BASE);
wdog3[1] = mmio_read_32(IMX_WDOG3_BASE + 0x8);
}
void wdog3_restore(void)
{
/* enable wdog3 clock */
mmio_write_32(IMX_PCC3_BASE + 0xa8, 0xd2800000);
/* reconfig the CS */
mmio_write_32(IMX_WDOG3_BASE, wdog3[0]);
/* set the tiemout value */
mmio_write_32(IMX_WDOG3_BASE + 0x8, wdog3[1]);
/* wait for the lock status */
while ((mmio_read_32(IMX_WDOG3_BASE) & BIT(11))) {
;
}
/* wait for the config done */
while (!(mmio_read_32(IMX_WDOG3_BASE) & BIT(10))) {
;
}
}
static uint32_t lpuart_regs[4];
#define LPUART_BAUD 0x10
#define LPUART_CTRL 0x18
#define LPUART_FIFO 0x28
#define LPUART_WATER 0x2c
void lpuart_save(void)
{
lpuart_regs[0] = mmio_read_32(IMX_LPUART5_BASE + LPUART_BAUD);
lpuart_regs[1] = mmio_read_32(IMX_LPUART5_BASE + LPUART_FIFO);
lpuart_regs[2] = mmio_read_32(IMX_LPUART5_BASE + LPUART_WATER);
lpuart_regs[3] = mmio_read_32(IMX_LPUART5_BASE + LPUART_CTRL);
}
void lpuart_restore(void)
{
mmio_write_32(IMX_LPUART5_BASE + LPUART_BAUD, lpuart_regs[0]);
mmio_write_32(IMX_LPUART5_BASE + LPUART_FIFO, lpuart_regs[1]);
mmio_write_32(IMX_LPUART5_BASE + LPUART_WATER, lpuart_regs[2]);
mmio_write_32(IMX_LPUART5_BASE + LPUART_CTRL, lpuart_regs[3]);
}
bool is_lpav_owned_by_apd(void)
{
return (mmio_read_32(0x2802b044) & BIT(7)) ? true : false;
}
void lpav_ctx_save(void)
{
unsigned int i;
uint32_t val;
/* CGC2 save */
for (i = 0U; i < ARRAY_SIZE(cgc2); i++) {
cgc2[i][1] = mmio_read_32(cgc2[i][0]);
}
/* PLL4 */
for (i = 0U; i < ARRAY_SIZE(pll4); i++) {
pll4[i][1] = mmio_read_32(pll4[i][0]);
}
/* PCC5 save */
for (i = 0U; i < ARRAY_SIZE(pcc5_0); i++) {
val = mmio_read_32(IMX_PCC5_BASE + i * 4);
if (val & PCC_PR) {
pcc5_0[i] = val;
}
}
for (i = 0U; i < ARRAY_SIZE(pcc5_1); i++) {
val = mmio_read_32(pcc5_1[i][0]);
if (val & PCC_PR) {
pcc5_1[i][1] = val;
}
}
/* LPAV SIM save */
for (i = 0U; i < ARRAY_SIZE(lpav_sim); i++) {
lpav_sim[i][1] = mmio_read_32(lpav_sim[i][0]);
}
/* Save GPIO port D */
gpio_save(&lpav_gpio_ctx, LPAV_GPIO_CTRL_NUM);
/* put DDR into retention */
dram_enter_retention();
}
void lpav_ctx_restore(void)
{
unsigned int i;
/* PLL4 */
for (i = 0U; i < 9U; i++) {
mmio_write_32(pll4[i][0], pll4[i][1]);
}
/* wait for PLL4 lock */
while (!(mmio_read_32(pll4[8][0]) & BIT(24))) {
;
}
/* restore the PLL4 PFDs */
mmio_write_32(pll4[9][0], pll4[9][1] & ~(BIT(31) | BIT(23) | BIT(15) | BIT(7)));
mmio_write_32(pll4[9][0], pll4[9][1]);
/* wait for the PFD is stable */
while (!(mmio_read_32(pll4[9][0]) & PFD_VALID_MASK)) {
;
}
/* CGC2 restore */
for (i = 0U; i < ARRAY_SIZE(cgc2); i++) {
mmio_write_32(cgc2[i][0], cgc2[i][1]);
}
/* PCC5 restore */
for (i = 0U; i < ARRAY_SIZE(pcc5_0); i++) {
if (pcc5_0[i] & PCC_PR) {
mmio_write_32(IMX_PCC5_BASE + i * 4, pcc5_0[i]);
}
}
for (i = 0U; i < ARRAY_SIZE(pcc5_1); i++) {
if (pcc5_1[i][1] & PCC_PR) {
mmio_write_32(pcc5_1[i][0], pcc5_1[i][1]);
}
}
/* LPAV_SIM */
for (i = 0U; i < ARRAY_SIZE(lpav_sim); i++) {
mmio_write_32(lpav_sim[i][0], lpav_sim[i][1]);
}
gpio_restore(&lpav_gpio_ctx, LPAV_GPIO_CTRL_NUM);
/* DDR retention exit */
dram_exit_retention();
}
void imx_apd_ctx_save(unsigned int proc_num)
{
unsigned int i;
uint32_t val;
/* enable LPUART5's clock by default */
mmio_setbits_32(IMX_PCC3_BASE + 0xe8, BIT(30));
/* save the gic config */
plat_gic_save(proc_num, &imx_gicv3_ctx);
cmc1_pmprot = mmio_read_32(IMX_CMC1_BASE + 0x18);
cmc1_srie = mmio_read_32(IMX_CMC1_BASE + 0x8c);
/* save the PCC3 */
for (i = 0U; i < ARRAY_SIZE(pcc3); i++) {
/* save the pcc if it is exist */
val = mmio_read_32(IMX_PCC3_BASE + i * 4);
if (val & PCC_PR) {
pcc3[i] = val;
}
}
/* save the PCC4 */
for (i = 0U; i < ARRAY_SIZE(pcc4); i++) {
/* save the pcc if it is exist */
val = mmio_read_32(IMX_PCC4_BASE + i * 4);
if (val & PCC_PR) {
pcc4[i] = val;
}
}
/* save the CGC1 */
cgc1_save();
wdog3_save();
gpio_save(apd_gpio_ctx, APD_GPIO_CTRL_NUM);
iomuxc_save();
tpm5_save();
lpuart_save();
/*
* save the lpav ctx & put the ddr into retention
* if lpav master is assigned to APD domain.
*/
if (is_lpav_owned_by_apd()) {
lpav_ctx_save();
}
}
void xrdc_reinit(void)
{
xrdc_apply_apd_config();
xrdc_apply_lpav_config();
xrdc_enable();
}
void s400_release_caam(void)
{
uint32_t msg, resp;
mmio_write_32(S400_MU_TRx(0), 0x17d70206);
mmio_write_32(S400_MU_TRx(1), 0x7);
do {
resp = mmio_read_32(S400_MU_RSR);
} while ((resp & 0x3) != 0x3);
msg = mmio_read_32(S400_MU_RRx(0));
resp = mmio_read_32(S400_MU_RRx(1));
VERBOSE("resp %x; %x", msg, resp);
}
void imx_apd_ctx_restore(unsigned int proc_num)
{
unsigned int i;
/* restore the CCG1 */
cgc1_restore();
for (i = 0U; i < ARRAY_SIZE(pcc3); i++) {
/* save the pcc if it is exist */
if (pcc3[i] & PCC_PR) {
mmio_write_32(IMX_PCC3_BASE + i * 4, pcc3[i]);
}
}
for (i = 0U; i < ARRAY_SIZE(pcc4); i++) {
if (pcc4[i] & PCC_PR) {
mmio_write_32(IMX_PCC4_BASE + i * 4, pcc4[i]);
}
}
wdog3_restore();
iomuxc_restore();
tpm5_restore();
xrdc_reinit();
/* Restore GPIO after xrdc_reinit, otherwise MSCs are invalid */
gpio_restore(apd_gpio_ctx, APD_GPIO_CTRL_NUM);
/* restore the gic config */
plat_gic_restore(proc_num, &imx_gicv3_ctx);
mmio_write_32(IMX_CMC1_BASE + 0x18, cmc1_pmprot);
mmio_write_32(IMX_CMC1_BASE + 0x8c, cmc1_srie);
/* enable LPUART5's clock by default */
mmio_setbits_32(IMX_PCC3_BASE + 0xe8, BIT(30));
/* restore the console lpuart */
lpuart_restore();
/* FIXME: make uart work for ATF */
mmio_write_32(IMX_LPUART_BASE + 0x18, 0xc0000);
/* Allow M core to reset A core */
mmio_clrbits_32(IMX_MU0B_BASE + 0x10, BIT(2));
/*
* Ask S400 to release caam to APD as it is owned by s400
*/
s400_release_caam();
/* re-init the caam */
imx8ulp_caam_init();
/*
* ack the upower, seems a necessary steps, otherwise the upower can
* not response to the new API service call. put this just before the
* ddr retention exit because that the dram retention exit flow need to
* communicate with upower.
*/
upower_wait_resp();
/*
* restore the lpav ctx & make ddr out of retention
* if lpav master is assigned to APD domain.
*/
if (is_lpav_owned_by_apd()) {
lpav_ctx_restore();
}
}
#define DGO_CTRL1 U(0xc)
#define USB_WAKEUP U(0x44)
#define USB1_PHY_DPD_WAKEUP_EN BIT_32(5)
#define USB0_PHY_DPD_WAKEUP_EN BIT_32(4)
#define USB1_PHY_WAKEUP_ISO_DISABLE BIT_32(1)
#define USB0_PHY_WAKEUP_ISO_DISABLE BIT_32(0)
void usb_wakeup_enable(bool enable)
{
if (enable) {
mmio_setbits_32(IMX_SIM1_BASE + USB_WAKEUP,
USB1_PHY_WAKEUP_ISO_DISABLE | USB0_PHY_WAKEUP_ISO_DISABLE);
mmio_setbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
while (!(mmio_read_32(IMX_SIM1_BASE + DGO_CTRL1) & BIT(1))) {
;
}
mmio_clrbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
mmio_write_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(1));
/* Need to delay for a while to make sure the wakeup logic can work */
udelay(500);
mmio_setbits_32(IMX_SIM1_BASE + USB_WAKEUP,
USB1_PHY_DPD_WAKEUP_EN | USB0_PHY_DPD_WAKEUP_EN);
mmio_setbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
while (!(mmio_read_32(IMX_SIM1_BASE + DGO_CTRL1) & BIT(1))) {
;
}
mmio_clrbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
mmio_write_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(1));
} else {
/*
* USBx_PHY_DPD_WAKEUP_EN should be cleared before USB0_PHY_WAKEUP_ISO_DISABLE
* to provide the correct the wake-up functionality.
*/
mmio_write_32(IMX_SIM1_BASE + USB_WAKEUP, USB1_PHY_WAKEUP_ISO_DISABLE |
USB0_PHY_WAKEUP_ISO_DISABLE);
mmio_write_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
while (!(mmio_read_32(IMX_SIM1_BASE + DGO_CTRL1) & BIT(1))) {
;
}
mmio_clrbits_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(0));
mmio_write_32(IMX_SIM1_BASE + DGO_CTRL1, BIT(1));
}
}

798
plat/imx/imx8ulp/dram.c Normal file
View file

@ -0,0 +1,798 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdbool.h>
#include <arch_helpers.h>
#include <bl31/interrupt_mgmt.h>
#include <common/runtime_svc.h>
#include <lib/mmio.h>
#include <lib/spinlock.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include <dram.h>
#include <upower_api.h>
#define PHY_FREQ_SEL_INDEX(x) ((x) << 16)
#define PHY_FREQ_MULTICAST_EN(x) ((x) << 8)
#define DENALI_PHY_1537 U(0x5804)
#define IMX_DDRC_BASE U(0x2E060000)
#define SAVED_DRAM_DATA_BASE U(0x20055000)
#define DENALI_CTL_143 U(0x23C)
#define DENALI_CTL_144 U(0x240)
#define DENALI_CTL_146 U(0x248)
#define LP_STATE_CS_IDLE U(0x404000)
#define LP_STATE_CS_PD_CG U(0x4F4F00)
#define LPI_WAKEUP_EN_SHIFT U(8)
#define IMX_LPAV_SIM_BASE 0x2DA50000
#define LPDDR_CTRL 0x14
#define LPDDR_AUTO_LP_MODE_DISABLE BIT(24)
#define SOC_LP_CMD_SHIFT U(15)
#define LPDDR_CTRL2 0x18
#define LPDDR_EN_CLKGATE (0x1<<17)
#define LPDDR_MAX_CLKDIV_EN (0x1 << 16)
#define LP_AUTO_ENTRY_EN 0x4
#define LP_AUTO_EXIT_EN 0xF
#define DENALI_CTL_00 U(0x0)
#define DENALI_CTL_23 U(0x5c)
#define DFIBUS_FREQ_INIT_SHIFT U(24)
#define TSREF2PHYMSTR_SHIFT U(8)
#define TSREF2PHYMSTR_MASK GENMASK(13, 8)
#define DENALI_CTL_24 U(0x60)
#define DENALI_CTL_25 U(0x64)
#define DENALI_CTL_93 U(0x174)
#define PWRUP_SREFRESH_EXIT BIT(0)
#define DENALI_CTL_127 U(0x1fc)
#define PHYMSTR_TRAIN_AFTER_INIT_COMPLETE BIT(16)
#define DENALI_CTL_147 U(0x24c)
#define DENALI_CTL_153 U(0x264)
#define PCPCS_PD_EN BIT(8)
#define DENALI_CTL_249 U(0x3E4)
#define DENALI_CTL_266 U(0x428)
#define DENALI_PHY_1547 U(0x582c)
#define PHY_LP4_BOOT_DISABLE BIT(8)
#define DENALI_PHY_1559 U(0x585c)
#define DENALI_PHY_1590 U(0x58D8)
#define DENALI_PI_00 U(0x2000)
#define DENALI_PI_04 U(0x2010)
#define DENALI_PI_52 U(0x20D0)
#define DENALI_PI_26 U(0x2068)
#define DENALI_PI_33 U(0x2084)
#define DENALI_PI_65 U(0x2104)
#define DENALI_PI_77 U(0x2134)
#define DENALI_PI_134 U(0x2218)
#define DENALI_PI_131 U(0x220C)
#define DENALI_PI_132 U(0x2210)
#define DENALI_PI_134 U(0x2218)
#define DENALI_PI_137 U(0x2224)
#define DENALI_PI_174 U(0x22B8)
#define DENALI_PI_175 U(0x22BC)
#define DENALI_PI_181 U(0x22D4)
#define DENALI_PI_182 U(0x22D8)
#define DENALI_PI_191 U(0x22FC)
#define DENALI_PI_192 U(0x2300)
#define DENALI_PI_212 U(0x2350)
#define DENALI_PI_214 U(0x2358)
#define DENALI_PI_217 U(0x2364)
#define LPDDR3_TYPE U(0x7)
#define LPDDR4_TYPE U(0xB)
extern void upower_wait_resp(void);
struct dram_cfg_param {
uint32_t reg;
uint32_t val;
};
struct dram_timing_info {
/* ddr controller config */
struct dram_cfg_param *ctl_cfg;
unsigned int ctl_cfg_num;
/* pi config */
struct dram_cfg_param *pi_cfg;
unsigned int pi_cfg_num;
/* phy freq1 config */
struct dram_cfg_param *phy_f1_cfg;
unsigned int phy_f1_cfg_num;
/* phy freq2 config */
struct dram_cfg_param *phy_f2_cfg;
unsigned int phy_f2_cfg_num;
/* automatic low power config */
struct dram_cfg_param *auto_lp_cfg;
unsigned int auto_lp_cfg_num;
/* initialized drate table */
unsigned int fsp_table[3];
};
#define CTL_NUM U(680)
#define PI_NUM U(298)
#define PHY_NUM U(1654)
#define PHY_DIFF_NUM U(49)
#define AUTO_LP_NUM U(3)
struct dram_cfg {
uint32_t ctl_cfg[CTL_NUM];
uint32_t pi_cfg[PI_NUM];
uint32_t phy_full[PHY_NUM];
uint32_t phy_diff[PHY_DIFF_NUM];
uint32_t auto_lp_cfg[AUTO_LP_NUM];
};
struct dram_timing_info *info;
struct dram_cfg *dram_timing_cfg;
/* mark if dram cfg is already saved */
static bool dram_cfg_saved;
static bool dram_auto_lp_true;
static uint32_t dram_class, dram_ctl_143;
/* PHY register index for frequency diff */
uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = {
90, 92, 93, 96, 97, 100, 101, 102, 103, 104, 114,
346, 348, 349, 352, 353, 356, 357, 358, 359, 360,
370, 602, 604, 605, 608, 609, 612, 613, 614, 615,
616, 626, 858, 860, 861, 864, 865, 868, 869, 870,
871, 872, 882, 1063, 1319, 1566, 1624, 1625
};
/* lock used for DDR DVFS */
spinlock_t dfs_lock;
static volatile uint32_t core_count;
static volatile bool in_progress;
static volatile bool sys_dvfs;
static int num_fsp;
static void ddr_init(void)
{
unsigned int i;
/* restore the ddr ctl config */
for (i = 0U; i < CTL_NUM; i++) {
mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]);
}
/* load the PI registers */
for (i = 0U; i < PI_NUM; i++) {
mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]);
}
/* restore all PHY registers for all the fsp. */
mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100);
/* restore all the phy configs */
for (i = 0U; i < PHY_NUM; i++) {
/* skip the reserved registers space */
if (i >= 121U && i <= 255U) {
continue;
}
if (i >= 377U && i <= 511U) {
continue;
}
if (i >= 633U && i <= 767U) {
continue;
}
if (i >= 889U && i <= 1023U) {
continue;
}
if (i >= 1065U && i <= 1279U) {
continue;
}
if (i >= 1321U && i <= 1535U) {
continue;
}
mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]);
}
if (dram_class == LPDDR4_TYPE) {
/* restore only the diff. */
mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
for (i = 0U; i < PHY_DIFF_NUM; i++) {
mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4,
dram_timing_cfg->phy_diff[i]);
}
}
/* Re-enable MULTICAST mode */
mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1));
}
void dram_lp_auto_disable(void)
{
uint32_t lp_auto_en;
dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
sizeof(struct dram_timing_info));
lp_auto_en = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) & (LP_AUTO_ENTRY_EN << 24));
/* Save initial config */
dram_ctl_143 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_143);
if (lp_auto_en && !dram_auto_lp_true) {
/* 0.a Save DDRC auto low-power mode parameter */
dram_timing_cfg->auto_lp_cfg[0] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144);
dram_timing_cfg->auto_lp_cfg[1] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_147);
dram_timing_cfg->auto_lp_cfg[2] = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146);
/* Set LPI_SRPD_LONG_MCCLK_GATE_WAKEUP_F2 to Maximum */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_143, 0xF << 24);
/* 0.b Disable DDRC auto low-power mode interface */
mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_146, LP_AUTO_ENTRY_EN << 24);
/* 0.c Read any location to get DRAM out of Self-refresh */
mmio_read_32(DEVICE2_BASE);
/* 0.d Confirm DRAM is out of Self-refresh */
while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) &
LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) {
;
}
/* 0.e Disable DDRC auto low-power exit */
mmio_clrbits_32(IMX_DDRC_BASE + DENALI_CTL_147, LP_AUTO_EXIT_EN);
/* dram low power mode flag */
dram_auto_lp_true = true;
}
}
void dram_lp_auto_enable(void)
{
/* Switch back to Auto Low-power mode */
if (dram_auto_lp_true) {
/* 12.a Confirm DRAM is out of Self-refresh */
while ((mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_146) &
LP_STATE_CS_PD_CG) != LP_STATE_CS_IDLE) {
;
}
/* 12.b Enable DDRC auto low-power exit */
/*
* 12.c TBC! : Set DENALI_CTL_144 [LPI_CTRL_REQ_EN[24]] and
* [DFI_LP_VERSION[16]] back to default settings = 1b'1.
*/
/*
* 12.d Reconfigure DENALI_CTL_144 [LPI_WAKEUP_EN[5:0]] bit
* LPI_WAKEUP_EN[3] = 1b'1.
*/
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, dram_timing_cfg->auto_lp_cfg[0]);
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_147, dram_timing_cfg->auto_lp_cfg[1]);
/* 12.e Re-enable DDRC auto low-power mode interface */
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_146, dram_timing_cfg->auto_lp_cfg[2]);
/* restore ctl config */
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_143, dram_ctl_143);
/* dram low power mode flag */
dram_auto_lp_true = false;
}
}
void dram_enter_self_refresh(void)
{
/* disable auto low power interface */
dram_lp_auto_disable();
/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
/* 1.a Clock gate PCC_LPDDR4[CGC] and no software reset PCC_LPDDR4[SWRST] */
mmio_setbits_32(IMX_PCC5_BASE + 0x108, (BIT(30) | BIT(28)));
/*
* 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
* LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
* long with mem and ctlr clk gating or self-refresh power-down long
* with mem and ctlr clk gating'
*/
mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
/* TODO: Needed ? 2.a DENALI_CTL_144[LPI_TIMER_WAKEUP_F2] */
//mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(0));
/*
* 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
* the logic to automatic handles low power entry/exit. This is the recommended
* option over handling through software.
* 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
* self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
* since LPPDR logic will be power gated).
*/
mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
/* 3.c clock gate ddr controller */
mmio_setbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_EN_CLKGATE);
/* 3.d lpddr max clk div en */
mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL2, LPDDR_MAX_CLKDIV_EN);
}
void dram_exit_self_refresh(void)
{
dram_lp_auto_enable();
}
void dram_enter_retention(void)
{
unsigned int i;
dram_lp_auto_disable();
/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
/*
* 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
* LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
* long with mem and ctlr clk gating or self-refresh power-down
* long with mem and ctlr clk gating'
*/
mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
/*
* 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
* the logic to automatic handles low power entry/exit. This is the recommended
* option over handling through software.
* 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
* self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
* since LPPDR logic will be power gated).
*/
mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
/* Save DDR Controller & PHY config.
* Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all
* the PHY registers for F2 into phy_f1_cfg, then read/store the diff between
* F1 & F2 into phy_f2_cfg.
*/
if (!dram_cfg_saved) {
info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
sizeof(struct dram_timing_info));
/* get the dram type */
dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00);
dram_class = (dram_class >> 8) & 0xf;
/* save the ctl registers */
for (i = 0U; i < CTL_NUM; i++) {
dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4);
}
dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE;
/* save the PI registers */
for (i = 0U; i < PI_NUM; i++) {
dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4);
}
dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE;
/*
* Read and store all PHY registers. full array is a full
* copy for all the setpoint
*/
if (dram_class == LPDDR4_TYPE) {
mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000);
for (i = 0U; i < PHY_NUM; i++) {
/* Make sure MULTICASE is enabled */
if (i == 1537U) {
dram_timing_cfg->phy_full[i] = 0x100;
} else {
dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4);
}
}
/*
* set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0.
* Read and store only the diff.
*/
mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
/* save only the frequency based diff config to save memory */
for (i = 0U; i < PHY_DIFF_NUM; i++) {
dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 +
freq_specific_reg_array[i] * 4);
}
} else {
/* LPDDR3, only f1 need to save */
for (i = 0U; i < info->phy_f1_cfg_num; i++) {
info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg);
}
}
dram_cfg_saved = true;
}
}
void dram_exit_retention(void)
{
uint32_t val;
/* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */
mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
/* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */
mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28));
/* 3. Reload the LPDDR CTL/PI/PHY register */
ddr_init();
if (dram_class == LPDDR4_TYPE) {
/* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */
mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101);
/*
* 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit
* from controller.
*/
/*
* 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling
* self refresh exit from PI
*/
/* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */
/*
* 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2=
* PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2.
* Enable non initialization trainings.
*/
/* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */
/* 4f. PI_DLL_RESET=0x1 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
/* PI_PWRUP_SELF_REF_EXIT = 1 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
/* PI_MC_PWRUP_SELF_REF_EXIT = 0 */
mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
/* PI_INT_LVL_EN = 0 */
mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
/* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000);
/* PI_WRLVL_EN_F2 = 3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03);
/* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000);
/* PI_CALVL_EN_F2 = 3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03);
/* PI_WDQLVL_EN_F0 = 3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300);
/* PI_WDQLVL_EN_F1 = 3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000);
/* PI_WDQLVL_EN_F2 = 3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300);
/* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
/*
* PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3,
* PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3
*/
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303);
/* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
} else {
/* PI_DLL_RESET=1 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
/* PI_PWRUP_SELF_REF_EXIT=1 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
/* PI_MC_PWRUP_SELF_REF_EXIT=0 */
mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
/* PI_INT_LVL_EN=0 */
mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
/* PI_WRLVL_EN_F0=3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000);
/* PI_CALVL_EN_F0=3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000);
/* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
/* PI_PWRUP_SREFRESH_EXIT_CS=0xF */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
}
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00);
/* Force in-order AXI read data */
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1);
/*
* Disable special R/W group switches so that R/W group placement
* is always at END of R/W group.
*/
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0);
/* Reduce time for IO pad calibration */
mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000);
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100);
/* PD disable */
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000);
/*
* 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN
* to 1b'0, PCPCS_PD_EN to 1b'0
*/
upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL);
upower_wait_resp();
if (dram_class == LPDDR4_TYPE) {
/* 7. Write PI START parameter to 1'b1 */
mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01);
/* 8. Write CTL START parameter to 1'b1 */
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01);
} else {
/* 7. Write PI START parameter to 1'b1 */
mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701);
/* 8. Write CTL START parameter to 1'b1 */
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701);
}
/* 9. DENALI_CTL_266: Wait for INT_STATUS_INIT=0x2 */
do {
val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF;
} while (val != 0x2);
/*
* 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ,
* PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order.
*/
if (dram_class == LPDDR4_TYPE) {
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */
/* 11. Wait for trainings to get complete by polling PI_INT_STATUS */
while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) {
;
}
} else {
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) {
;
}
}
dram_lp_auto_enable();
}
#define LPDDR_DONE (0x1<<4)
#define SOC_FREQ_CHG_ACK (0x1<<6)
#define SOC_FREQ_CHG_REQ (0x1<<7)
#define LPI_WAKEUP_EN (0x4<<8)
#define SOC_FREQ_REQ (0x1<<11)
static void set_cgc2_ddrclk(uint8_t src, uint8_t div)
{
/* Wait until the reg is unlocked for writing */
while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31))
;
mmio_write_32(IMX_CGC2_BASE + 0x40, (src << 28) | (div << 21));
/* Wait for the clock switching done */
while (!(mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(27)))
;
}
static void set_ddr_clk(uint32_t ddr_freq)
{
/* Disable DDR clock */
mmio_clrbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
switch (ddr_freq) {
/* boot frequency ? */
case 48:
set_cgc2_ddrclk(2, 0);
break;
/* default bypass frequency for fsp 1 */
case 192:
set_cgc2_ddrclk(0, 1);
break;
case 384:
set_cgc2_ddrclk(0, 0);
break;
case 264:
set_cgc2_ddrclk(4, 3);
break;
case 528:
set_cgc2_ddrclk(4, 1);
break;
default:
break;
}
/* Enable DDR clock */
mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
/* Wait until the reg is unlocked for writing */
while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31)) {
;
}
}
#define AVD_SIM_LPDDR_CTRL (IMX_LPAV_SIM_BASE + 0x14)
#define AVD_SIM_LPDDR_CTRL2 (IMX_LPAV_SIM_BASE + 0x18)
#define MAX_FSP_NUM U(3)
#define DDR_DFS_GET_FSP_COUNT 0x10
#define DDR_BYPASS_DRATE U(400)
extern int upower_pmic_i2c_write(uint32_t reg_addr, uint32_t reg_val);
/* Normally, we only switch frequency between 1(bypass) and 2(highest) */
int lpddr4_dfs(uint32_t freq_index)
{
uint32_t lpddr_ctrl, lpddr_ctrl2;
uint32_t ddr_ctl_144;
/*
* Valid index: 0 to 2
* index 0: boot frequency
* index 1: bypass frequency
* index 2: highest frequency
*/
if (freq_index > 2U) {
return -1;
}
/*
* increase the voltage to 1.1V firstly before increase frequency
* and APD enter OD mode
*/
if (freq_index == 2U && sys_dvfs) {
upower_pmic_i2c_write(0x22, 0x28);
}
/* Enable LPI_WAKEUP_EN */
ddr_ctl_144 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144);
mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, LPI_WAKEUP_EN);
/* put DRAM into long self-refresh & clock gating */
lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
lpddr_ctrl = (lpddr_ctrl & ~((0x3f << 15) | (0x3 << 9))) | (0x28 << 15) | (freq_index << 9);
mmio_write_32(AVD_SIM_LPDDR_CTRL, lpddr_ctrl);
/* Gating the clock */
lpddr_ctrl2 = mmio_read_32(AVD_SIM_LPDDR_CTRL2);
mmio_setbits_32(AVD_SIM_LPDDR_CTRL2, LPDDR_EN_CLKGATE);
/* Request frequency change */
mmio_setbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_REQ);
do {
lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
if (lpddr_ctrl & SOC_FREQ_CHG_REQ) {
/* Bypass mode */
if (info->fsp_table[freq_index] < DDR_BYPASS_DRATE) {
/* Change to PLL bypass mode */
mmio_write_32(IMX_LPAV_SIM_BASE, 0x1);
/* change the ddr clock source & frequency */
set_ddr_clk(info->fsp_table[freq_index]);
} else {
/* Change to PLL unbypass mode */
mmio_write_32(IMX_LPAV_SIM_BASE, 0x0);
/* change the ddr clock source & frequency */
set_ddr_clk(info->fsp_table[freq_index] >> 1);
}
mmio_clrsetbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_CHG_REQ, SOC_FREQ_CHG_ACK);
continue;
}
} while ((lpddr_ctrl & LPDDR_DONE) != 0); /* several try? */
/* restore the original setting */
mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, ddr_ctl_144);
mmio_write_32(AVD_SIM_LPDDR_CTRL2, lpddr_ctrl2);
/* Check the DFS result */
lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL) & 0xF;
if (lpddr_ctrl != 0U) {
/* Must be something wrong, return failure */
return -1;
}
/* decrease the BUCK3 voltage after frequency changed to lower
* and APD in ND_MODE
*/
if (freq_index == 1U && sys_dvfs) {
upower_pmic_i2c_write(0x22, 0x20);
}
/* DFS done successfully */
return 0;
}
/* for the non-primary core, waiting for DFS done */
static uint64_t waiting_dvfs(uint32_t id, uint32_t flags,
void *handle, void *cookie)
{
uint32_t irq;
irq = plat_ic_acknowledge_interrupt();
if (irq < 1022U) {
plat_ic_end_of_interrupt(irq);
}
/* set the WFE done status */
spin_lock(&dfs_lock);
core_count++;
dsb();
spin_unlock(&dfs_lock);
while (in_progress) {
wfe();
}
return 0;
}
int dram_dvfs_handler(uint32_t smc_fid, void *handle,
u_register_t x1, u_register_t x2, u_register_t x3)
{
unsigned int fsp_index = x1;
uint32_t online_cpus = x2 - 1;
uint64_t mpidr = read_mpidr_el1();
unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
/* Get the number of FSPs */
if (x1 == DDR_DFS_GET_FSP_COUNT) {
SMC_RET2(handle, num_fsp, info->fsp_table[1]);
}
/* start lpddr frequency scaling */
in_progress = true;
sys_dvfs = x3 ? true : false;
dsb();
/* notify other core wait for scaling done */
for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++)
/* Skip raise SGI for current CPU */
if (i != cpu_id) {
plat_ic_raise_el3_sgi(0x8, i);
}
/* Make sure all the cpu in WFE */
while (online_cpus != core_count) {
;
}
/* Flush the L1/L2 cache */
dcsw_op_all(DCCSW);
lpddr4_dfs(fsp_index);
in_progress = false;
core_count = 0;
dsb();
sev();
isb();
SMC_RET1(handle, 0);
}
void dram_init(void)
{
uint32_t flags = 0;
uint32_t rc;
unsigned int i;
/* Register the EL3 handler for DDR DVFS */
set_interrupt_rm_flag(flags, NON_SECURE);
rc = register_interrupt_type_handler(INTR_TYPE_EL3, waiting_dvfs, flags);
if (rc) {
panic();
}
info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
/* Get the num of the supported Fsp */
for (i = 0; i < MAX_FSP_NUM; i++) {
if (!info->fsp_table[i]) {
break;
}
}
num_fsp = (i > MAX_FSP_NUM) ? MAX_FSP_NUM : i;
}

View file

@ -0,0 +1,186 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdbool.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <context.h>
#include <drivers/console.h>
#include <drivers/generic_delay_timer.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/mmio.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include <dram.h>
#include <imx8_lpuart.h>
#include <imx8ulp_caam.h>
#include <imx_plat_common.h>
#include <plat_imx8.h>
#include <upower_api.h>
#include <xrdc.h>
#define MAP_BL31_TOTAL \
MAP_REGION_FLAT(BL31_BASE, BL31_LIMIT - BL31_BASE, MT_MEMORY | MT_RW | MT_SECURE)
#define MAP_BL31_RO \
MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_MEMORY | MT_RO | MT_SECURE)
#define MAP_BL32_TOTAL MAP_REGION_FLAT(BL32_BASE, BL32_SIZE, MT_MEMORY | MT_RW)
#define MAP_COHERENT_MEM \
MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, (BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE), \
MT_DEVICE | MT_RW | MT_SECURE)
#define TRUSTY_PARAMS_LEN_BYTES (4096*2)
static const mmap_region_t imx_mmap[] = {
DEVICE0_MAP, DEVICE1_MAP, DEVICE2_MAP,
ELE_MAP, SEC_SIM_MAP, SRAM0_MAP,
{0}
};
extern uint32_t upower_init(void);
extern void imx8ulp_init_scmi_server(void);
static entry_point_info_t bl32_image_ep_info;
static entry_point_info_t bl33_image_ep_info;
void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
static console_t console;
/* config the TPM5 clock */
mmio_write_32(IMX_PCC3_BASE + 0xd0, 0x92000000);
mmio_write_32(IMX_PCC3_BASE + 0xd0, 0xd2000000);
/* enable the GPIO D,E,F non-secure access by default */
mmio_write_32(IMX_PCC4_BASE + 0x78, 0xc0000000);
mmio_write_32(IMX_PCC4_BASE + 0x7c, 0xc0000000);
mmio_write_32(IMX_PCC5_BASE + 0x114, 0xc0000000);
mmio_write_32(IMX_GPIOE_BASE + 0x10, 0xffffffff);
mmio_write_32(IMX_GPIOE_BASE + 0x14, 0x3);
mmio_write_32(IMX_GPIOE_BASE + 0x18, 0xffffffff);
mmio_write_32(IMX_GPIOE_BASE + 0x1c, 0x3);
mmio_write_32(IMX_GPIOF_BASE + 0x10, 0xffffffff);
mmio_write_32(IMX_GPIOF_BASE + 0x14, 0x3);
mmio_write_32(IMX_GPIOF_BASE + 0x18, 0xffffffff);
mmio_write_32(IMX_GPIOF_BASE + 0x1c, 0x3);
mmio_write_32(IMX_GPIOD_BASE + 0x10, 0xffffffff);
mmio_write_32(IMX_GPIOD_BASE + 0x14, 0x3);
mmio_write_32(IMX_GPIOD_BASE + 0x18, 0xffffffff);
mmio_write_32(IMX_GPIOD_BASE + 0x1c, 0x3);
console_lpuart_register(IMX_LPUART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
IMX_CONSOLE_BAUDRATE, &console);
/* This console is only used for boot stage */
console_set_scope(&console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET;
bl33_image_ep_info.spsr = plat_get_spsr_for_bl33_entry();
SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
#if defined(SPD_opteed) || defined(SPD_trusty)
/* Populate entry point information for BL32 */
SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
bl32_image_ep_info.pc = BL32_BASE;
bl32_image_ep_info.spsr = 0;
/* Pass TEE base and size to bl33 */
bl33_image_ep_info.args.arg1 = BL32_BASE;
bl33_image_ep_info.args.arg2 = BL32_SIZE;
#ifdef SPD_trusty
bl32_image_ep_info.args.arg0 = BL32_SIZE;
bl32_image_ep_info.args.arg1 = BL32_BASE;
#else
/* Make sure memory is clean */
mmio_write_32(BL32_FDT_OVERLAY_ADDR, 0);
bl33_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
bl32_image_ep_info.args.arg3 = BL32_FDT_OVERLAY_ADDR;
#endif
#endif
}
void bl31_plat_arch_setup(void)
{
const mmap_region_t bl_regions[] = {
MAP_BL31_TOTAL,
MAP_BL31_RO,
#if USE_COHERENT_MEM
MAP_COHERENT_MEM,
#endif
#if defined(SPD_opteed) || defined(SPD_trusty)
MAP_BL32_TOTAL,
#endif
{0},
};
setup_page_tables(bl_regions, imx_mmap);
enable_mmu_el3(0);
/* TODO: Hack, refine this piece, scmi channel free */
mmio_write_32(SRAM0_BASE + 0x4, 1);
/* Allow M core to reset A core */
mmio_clrbits_32(IMX_MU0B_BASE + 0x10, BIT(2));
}
void bl31_platform_setup(void)
{
/* select the arch timer source */
mmio_setbits_32(IMX_SIM1_BASE + 0x30, 0x8000000);
generic_delay_timer_init();
plat_gic_driver_init();
plat_gic_init();
imx8ulp_init_scmi_server();
upower_init();
xrdc_apply_apd_config();
xrdc_apply_lpav_config();
xrdc_enable();
imx8ulp_caam_init();
dram_init();
}
entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
{
if (type == NON_SECURE) {
return &bl33_image_ep_info;
} else {
return &bl32_image_ep_info;
}
}
unsigned int plat_get_syscnt_freq2(void)
{
return COUNTER_FREQUENCY;
}
void bl31_plat_runtime_setup(void)
{
}
#ifdef SPD_trusty
void plat_trusty_set_boot_args(aapcs64_params_t *args)
{
args->arg0 = BL32_SIZE;
args->arg1 = BL32_BASE;
args->arg2 = TRUSTY_PARAMS_LEN_BYTES;
}
#endif

View file

@ -0,0 +1,18 @@
/*
* Copyright 2021-2024 NXP.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/mmio.h>
#include <imx8ulp_caam.h>
void imx8ulp_caam_init(void)
{
/* config CAAM JRaMID set MID to Cortex A */
mmio_write_32(CAAM_JR0MID, CAAM_NS_MID);
mmio_write_32(CAAM_JR1MID, CAAM_NS_MID);
mmio_write_32(CAAM_JR2MID, CAAM_NS_MID);
mmio_write_32(CAAM_JR3MID, CAAM_NS_MID);
}

View file

@ -0,0 +1,555 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdbool.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/arm/gicv3.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <plat_imx8.h>
#include <upower_api.h>
extern void cgc1_save(void);
extern void cgc1_restore(void);
extern void imx_apd_ctx_save(unsigned int cpu);
extern void imx_apd_ctx_restore(unsigned int cpu);
extern void usb_wakeup_enable(bool enable);
extern void upower_wait_resp(void);
extern bool is_lpav_owned_by_apd(void);
extern void apd_io_pad_off(void);
extern int upower_pmic_i2c_read(uint32_t reg_addr, uint32_t *reg_val);
extern void imx8ulp_init_scmi_server(void);
static uintptr_t secure_entrypoint;
#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
#define RVBARADDRx(c) (IMX_SIM1_BASE + 0x5c + 0x4 * (c))
#define WKPUx(c) (IMX_SIM1_BASE + 0x3c + 0x4 * (c))
#define AD_COREx_LPMODE(c) (IMX_CMC1_BASE + 0x50 + 0x4 * (c))
#define PMIC_CFG(v, m, msk) \
{ \
.volt = (v), \
.mode = (m), \
.mode_msk = (msk), \
}
#define PAD_CFG(c, r, t) \
{ \
.pad_close = (c), \
.pad_reset = (r), \
.pad_tqsleep = (t) \
}
#define BIAS_CFG(m, n, p, mbias) \
{ \
.dombias_cfg = { \
.mode = (m), \
.rbbn = (n), \
.rbbp = (p), \
}, \
.membias_cfg = {mbias}, \
}
#define SWT_BOARD(swt_on, msk) \
{ \
.on = (swt_on), \
.mask = (msk), \
}
#define SWT_MEM(a, p, m) \
{ \
.array = (a), \
.perif = (p), \
.mask = (m), \
}
static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry)
{
mmio_write_32(RVBARADDRx(cpu), entry);
/* set update bit */
mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu));
/* wait for ack */
while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) {
}
/* clear update bit */
mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu));
/* clear ack bit */
mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu));
return 0;
}
static volatile uint32_t cgc1_nicclk;
int imx_pwr_domain_on(u_register_t mpidr)
{
unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr);
imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
/* slow down the APD NIC bus clock */
cgc1_nicclk = mmio_read_32(IMX_CGC1_BASE + 0x34);
mmio_clrbits_32(IMX_CGC1_BASE + 0x34, GENMASK_32(29, 28));
mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0);
/* enable wku wakeup for idle */
mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff);
return PSCI_E_SUCCESS;
}
void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
plat_gic_pcpu_init();
plat_gic_cpuif_enable();
/* set APD NIC back to orignally setting */
mmio_write_32(IMX_CGC1_BASE + 0x34, cgc1_nicclk);
}
int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
{
return PSCI_E_SUCCESS;
}
void imx_pwr_domain_off(const psci_power_state_t *target_state)
{
unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
plat_gic_cpuif_disable();
/* disable wakeup */
mmio_write_32(WKPUx(cpu), 0);
/* set core power mode to PD */
mmio_write_32(AD_COREx_LPMODE(cpu), 0x3);
}
/* APD power mode config */
ps_apd_pwr_mode_cfgs_t apd_pwr_mode_cfgs = {
[DPD_PWR_MODE] = {
.swt_board_offs = 0x180,
.swt_mem_offs = 0x188,
.pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
.pad_cfg = PAD_CFG(0x0, 0xc, 0x01e80a02),
.bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
},
/* PD */
[PD_PWR_MODE] = {
.swt_board_offs = 0x170,
.swt_mem_offs = 0x178,
.pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
.pad_cfg = PAD_CFG(0x0, 0xc, 0x01e80a00),
.bias_cfg = BIAS_CFG(0x0, 0x2, 0x2, 0x0),
},
[ADMA_PWR_MODE] = {
.swt_board_offs = 0x120,
.swt_mem_offs = 0x128,
.pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
.pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
.bias_cfg = BIAS_CFG(0x2, 0x2, 0x2, 0x0),
},
[ACT_PWR_MODE] = {
.swt_board_offs = 0x110,
.swt_mem_offs = 0x118,
.pmic_cfg = PMIC_CFG(0x23, 0x0, 0x2),
.pad_cfg = PAD_CFG(0x0, 0x0, 0x0deb7a00),
.bias_cfg = BIAS_CFG(0x2, 0x2, 0x2, 0x0),
},
};
/* APD power switch config */
ps_apd_swt_cfgs_t apd_swt_cfgs = {
[DPD_PWR_MODE] = {
.swt_board[0] = SWT_BOARD(0x0, 0x1fffc),
.swt_mem[0] = SWT_MEM(0x0, 0x0, 0x1ffff),
.swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
},
[PD_PWR_MODE] = {
.swt_board[0] = SWT_BOARD(0x0, 0x00001fffc),
.swt_mem[0] = SWT_MEM(0x00010c00, 0x0, 0x1ffff),
.swt_mem[1] = SWT_MEM(0x003fffff, 0x003f0000, 0x0),
},
[ADMA_PWR_MODE] = {
.swt_board[0] = SWT_BOARD(0x15f74, 0x15f74),
.swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
.swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
},
[ACT_PWR_MODE] = {
.swt_board[0] = SWT_BOARD(0x15f74, 0x15f74),
.swt_mem[0] = SWT_MEM(0x0001fffd, 0x0001fffd, 0x1ffff),
.swt_mem[1] = SWT_MEM(0x003fffff, 0x003fffff, 0x0),
},
};
/* PMIC config for power down, LDO1 should be OFF */
ps_apd_pmic_reg_data_cfgs_t pd_pmic_reg_cfgs = {
[0] = {
.tag = PMIC_REG_VALID_TAG,
.power_mode = PD_PWR_MODE,
.i2c_addr = 0x30,
.i2c_data = 0x9c,
},
[1] = {
.tag = PMIC_REG_VALID_TAG,
.power_mode = PD_PWR_MODE,
.i2c_addr = 0x22,
.i2c_data = 0xb,
},
[2] = {
.tag = PMIC_REG_VALID_TAG,
.power_mode = ACT_PWR_MODE,
.i2c_addr = 0x30,
.i2c_data = 0x9d,
},
[3] = {
.tag = PMIC_REG_VALID_TAG,
.power_mode = ACT_PWR_MODE,
.i2c_addr = 0x22,
.i2c_data = 0x28,
},
};
/* PMIC config for deep power down, BUCK3 should be OFF */
ps_apd_pmic_reg_data_cfgs_t dpd_pmic_reg_cfgs = {
[0] = {
.tag = PMIC_REG_VALID_TAG,
.power_mode = DPD_PWR_MODE,
.i2c_addr = 0x21,
.i2c_data = 0x78,
},
[1] = {
.tag = PMIC_REG_VALID_TAG,
.power_mode = DPD_PWR_MODE,
.i2c_addr = 0x30,
.i2c_data = 0x9c,
},
[2] = {
.tag = PMIC_REG_VALID_TAG,
.power_mode = ACT_PWR_MODE,
.i2c_addr = 0x21,
.i2c_data = 0x79,
},
[3] = {
.tag = PMIC_REG_VALID_TAG,
.power_mode = ACT_PWR_MODE,
.i2c_addr = 0x30,
.i2c_data = 0x9d,
},
};
struct ps_pwr_mode_cfg_t *pwr_sys_cfg = (struct ps_pwr_mode_cfg_t *)UPWR_DRAM_SHARED_BASE_ADDR;
void imx_set_pwr_mode_cfg(abs_pwr_mode_t mode)
{
uint32_t volt;
if (mode >= NUM_PWR_MODES) {
return;
}
/* apd power mode config */
memcpy(&pwr_sys_cfg->ps_apd_pwr_mode_cfg[mode], &apd_pwr_mode_cfgs[mode],
sizeof(struct ps_apd_pwr_mode_cfg_t));
/* apd power switch config */
memcpy(&pwr_sys_cfg->ps_apd_swt_cfg[mode], &apd_swt_cfgs[mode], sizeof(swt_config_t));
/*
* BUCK3 & LDO1 can only be shutdown when LPAV is owned by APD side
* otherwise RTD side is responsible to control them in low power mode.
*/
if (is_lpav_owned_by_apd()) {
/* power off the BUCK3 in DPD mode */
if (mode == DPD_PWR_MODE) {
memcpy(&pwr_sys_cfg->ps_apd_pmic_reg_data_cfg, &dpd_pmic_reg_cfgs,
sizeof(ps_apd_pmic_reg_data_cfgs_t));
/* LDO1 should be power off in PD mode */
} else if (mode == PD_PWR_MODE) {
/* overwrite the buck3 voltage setting in active mode */
upower_pmic_i2c_read(0x22, &volt);
pd_pmic_reg_cfgs[3].i2c_data = volt;
memcpy(&pwr_sys_cfg->ps_apd_pmic_reg_data_cfg, &pd_pmic_reg_cfgs,
sizeof(ps_apd_pmic_reg_data_cfgs_t));
}
}
}
void imx_domain_suspend(const psci_power_state_t *target_state)
{
unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
if (is_local_state_off(CORE_PWR_STATE(target_state))) {
plat_gic_cpuif_disable();
imx_pwr_set_cpu_entry(cpu, secure_entrypoint);
/* core put into power down */
mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x3);
/* FIXME config wakeup interrupt in WKPU */
mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
} else {
/* for core standby/retention mode */
mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x1);
mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x7fffffe3);
dsb();
write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
isb();
}
if (is_local_state_retn(CLUSTER_PWR_STATE(target_state))) {
/*
* just for sleep mode for now, need to update to
* support more modes, same for suspend finish call back.
*/
mmio_write_32(IMX_CMC1_BASE + 0x10, 0x1);
mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1);
} else if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
/*
* for cluster off state, put cluster into power down mode,
* config the cluster clock to be off.
*/
mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
mmio_write_32(IMX_CMC1_BASE + 0x20, 0xf);
}
if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
/*
* low power mode config info used by upower
* to do low power mode transition.
*/
imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
imx_set_pwr_mode_cfg(ACT_PWR_MODE);
imx_set_pwr_mode_cfg(PD_PWR_MODE);
/* clear the upower wakeup */
upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
upower_wait_resp();
/* enable the USB wakeup */
usb_wakeup_enable(true);
/* config the WUU to enabled the wakeup source */
mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
/* !!! clear all the pad wakeup pending event */
mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
/* enable upower usb phy wakeup by default */
mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4) | BIT(1) | BIT(0));
/* enabled all pad wakeup by default */
mmio_write_32(IMX_WUU1_BASE + 0x8, 0xffffffff);
/* save the AD domain context before entering PD mode */
imx_apd_ctx_save(cpu);
}
}
#define DRAM_LPM_STATUS U(0x2802b004)
void imx_domain_suspend_finish(const psci_power_state_t *target_state)
{
unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1());
if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
/* restore the ap domain context */
imx_apd_ctx_restore(cpu);
/* clear the upower wakeup */
upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
upower_wait_resp();
/* disable all pad wakeup */
mmio_write_32(IMX_WUU1_BASE + 0x8, 0x0);
/* clear all the pad wakeup pending event */
mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
/*
* disable the usb wakeup after resume to make sure the pending
* usb wakeup in WUU can be cleared successfully, otherwise,
* APD will resume failed in next PD mode.
*/
usb_wakeup_enable(false);
/* re-init the SCMI channel */
imx8ulp_init_scmi_server();
}
/*
* wait for DDR is ready when DDR is under the RTD
* side control for power saving
*/
while (mmio_read_32(DRAM_LPM_STATUS) != 0) {
;
}
/*
* when resume from low power mode, need to delay for a while
* before access the CMC register.
*/
udelay(5);
/* clear cluster's LPM setting. */
mmio_write_32(IMX_CMC1_BASE + 0x20, 0x0);
mmio_write_32(IMX_CMC1_BASE + 0x10, 0x0);
/* clear core's LPM setting */
mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0x0);
mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0x0);
if (is_local_state_off(CORE_PWR_STATE(target_state))) {
imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
plat_gic_cpuif_enable();
} else {
dsb();
write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
isb();
}
}
void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
{
while (1) {
wfi();
}
}
void __dead2 imx8ulp_system_reset(void)
{
imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY);
/* Write invalid command to WDOG CNT to trigger reset */
mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678);
while (true) {
wfi();
}
}
int imx_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
int pwr_type = psci_get_pstate_type(power_state);
if (pwr_lvl > PLAT_MAX_PWR_LVL) {
return PSCI_E_INVALID_PARAMS;
}
if (pwr_type == PSTATE_TYPE_STANDBY) {
CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
}
/* No power down state support */
if (pwr_type == PSTATE_TYPE_POWERDOWN) {
return PSCI_E_INVALID_PARAMS;
}
return PSCI_E_SUCCESS;
}
void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
unsigned int i;
for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) {
req_state->pwr_domain_state[i] = PLAT_POWER_DOWN_OFF_STATE;
}
}
void __dead2 imx_system_off(void)
{
unsigned int i;
/* config the all the core into OFF mode and IRQ masked. */
for (i = 0U; i < PLATFORM_CORE_COUNT; i++) {
/* disable wakeup from wkpu */
mmio_write_32(WKPUx(i), 0x0);
/* reset the core reset entry to 0x1000 */
imx_pwr_set_cpu_entry(i, 0x1000);
/* config the core power mode to off */
mmio_write_32(AD_COREx_LPMODE(i), 0x3);
}
plat_gic_cpuif_disable();
/* power off all the pad */
apd_io_pad_off();
/* Config the power mode info for entering DPD mode and ACT mode */
imx_set_pwr_mode_cfg(ADMA_PWR_MODE);
imx_set_pwr_mode_cfg(ACT_PWR_MODE);
imx_set_pwr_mode_cfg(DPD_PWR_MODE);
/* Set the APD domain into DPD mode */
mmio_write_32(IMX_CMC1_BASE + 0x10, 0x7);
mmio_write_32(IMX_CMC1_BASE + 0x20, 0x1f);
/* make sure no pending upower wakeup */
upwr_xcp_set_rtd_apd_llwu(APD_DOMAIN, 0, NULL);
upower_wait_resp();
/* enable the upower wakeup from wuu, act as APD boot up method */
mmio_write_32(IMX_PCC3_BASE + 0x98, 0xc0800000);
mmio_setbits_32(IMX_WUU1_BASE + 0x18, BIT(4));
/* make sure no pad wakeup event is pending */
mmio_write_32(IMX_WUU1_BASE + 0x20, 0xffffffff);
wfi();
ERROR("power off failed.\n");
panic();
}
static const plat_psci_ops_t imx_plat_psci_ops = {
.pwr_domain_on = imx_pwr_domain_on,
.pwr_domain_on_finish = imx_pwr_domain_on_finish,
.validate_ns_entrypoint = imx_validate_ns_entrypoint,
.system_off = imx_system_off,
.system_reset = imx8ulp_system_reset,
.pwr_domain_off = imx_pwr_domain_off,
.pwr_domain_suspend = imx_domain_suspend,
.pwr_domain_suspend_finish = imx_domain_suspend_finish,
.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
.validate_power_state = imx_validate_power_state,
.pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi,
};
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
secure_entrypoint = sec_entrypoint;
imx_pwr_set_cpu_entry(0, sec_entrypoint);
*psci_ops = &imx_plat_psci_ops;
mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f);
mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff);
return 0;
}

View file

@ -0,0 +1,13 @@
/*
* Copyright 2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef DRAM_H
#define DRAM_H
void dram_init(void);
#endif /* DRAM_H */

View file

@ -0,0 +1,24 @@
/*
* Copyright 2021-2024 NXP.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IMX8ULP_CAAM_H
#define IMX8ULP_CAAM_H
#include <lib/utils_def.h>
#include <platform_def.h>
#define CAAM_JR0MID (IMX_CAAM_BASE + 0x10)
#define CAAM_JR1MID (IMX_CAAM_BASE + 0x18)
#define CAAM_JR2MID (IMX_CAAM_BASE + 0x20)
#define CAAM_JR3MID (IMX_CAAM_BASE + 0x28)
#define CAAM_NS_MID (0x7)
#define JR0_BASE (IMX_CAAM_BASE + 0x1000)
void imx8ulp_caam_init(void);
#endif /* IMX8ULP_CAAM_H */

View file

@ -0,0 +1,124 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLATFORM_DEF_H
#define PLATFORM_DEF_H
#include <lib/utils_def.h>
#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
#define PLATFORM_LINKER_ARCH aarch64
#define PLATFORM_STACK_SIZE 0x400
#define CACHE_WRITEBACK_GRANULE 64
#define PLAT_PRIMARY_CPU 0x0
#define PLATFORM_MAX_CPU_PER_CLUSTER 2
#define PLATFORM_CLUSTER_COUNT 1
#define PLATFORM_CORE_COUNT 2
#define PLATFORM_CLUSTER0_CORE_COUNT 2
#define PLATFORM_CLUSTER1_CORE_COUNT 0
#define IMX_PWR_LVL0 MPIDR_AFFLVL0
#define IMX_PWR_LVL1 MPIDR_AFFLVL1
#define IMX_PWR_LVL2 MPIDR_AFFLVL2
#define PWR_DOMAIN_AT_MAX_LVL U(1)
#define PLAT_MAX_PWR_LVL U(2)
#define PLAT_SLEEP_RET_STATE U(1)
#define PLAT_DEEP_SLEEP_RET_STATE U(2)
#define PLAT_MAX_RET_STATE U(3)
#define PLAT_POWER_DOWN_OFF_STATE U(4)
#define PLAT_DEEP_POWER_DOWN_STATE U(5)
#define PLAT_MAX_OFF_STATE U(6)
#define BL31_BASE 0x20040000
#define BL31_LIMIT 0x20070000
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32)
#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32)
#ifdef SPD_trusty
#define MAX_XLAT_TABLES 11
#define MAX_MMAP_REGIONS 12
#else
#define MAX_XLAT_TABLES 10
#define MAX_MMAP_REGIONS 11
#endif
#define PLAT_GICD_BASE U(0x2d400000)
#define PLAT_GICR_BASE U(0x2d440000)
#define DEVICE0_BASE U(0x20000000)
#define DEVICE0_SIZE U(0x10000000)
#define DEVICE1_BASE U(0x30000000)
#define DEVICE1_SIZE U(0x10000000)
#define DEVICE2_BASE U(0x8ff00000)
#define DEVICE2_SIZE U(0x00001000)
#define IMX_LPUART4_BASE U(0x29390000)
#define IMX_LPUART5_BASE U(0x293a0000)
#define IMX_LPUART_BASE IMX_LPUART5_BASE
#define IMX_CAAM_BASE U(0x292e0000)
#define IMX_BOOT_UART_CLK_IN_HZ 24000000
#define IMX_CONSOLE_BAUDRATE 115200
#define IMX_CGC1_BASE U(0x292c0000)
#define IMX_PCC3_BASE U(0x292d0000)
#define IMX_PCC4_BASE U(0x29800000)
#define IMX_SIM2_BASE U(0x2da50000)
#define IMX_CGC2_BASE U(0x2da60000)
#define IMX_PCC5_BASE U(0x2da70000)
#define IMX_MU0B_BASE U(0x29220000)
#define IMX_CMC1_BASE U(0x29240000)
#define IMX_WUU1_BASE U(0x29260000)
#define IMX_SIM1_BASE U(0x29290000)
#define IMX_GPIOD_BASE U(0x2e200000)
#define IMX_GPIOE_BASE U(0x2d000000)
#define IMX_GPIOF_BASE U(0x2d010000)
#define IMX_WDOG3_BASE U(0x292a0000)
#define IMX_TPM5_BASE U(0x29340000)
#define SRAM0_BASE U(0x2201F000)
#define IOMUXC_PTD_PCR_BASE U(0x298c0000)
#define IOMUXC_PTE_PCR_BASE U(0x298c0080)
#define IOMUXC_PTF_PCR_BASE U(0x298c0100)
#define IOMUXC_PSMI_BASE0 U(0x298c0800)
#define IOMUXC_PSMI_BASE1 U(0x298c0838)
#define IOMUXC_PSMI_BASE2 U(0x298c0954)
#define IOMUXC_PSMI_BASE3 U(0x298c0994)
#define IOMUXC_PSMI_BASE4 U(0x298c0a58)
#define IMX_ROM_ENTRY U(0x1000)
#define COUNTER_FREQUENCY 1000000
#define PLAT_NS_IMAGE_OFFSET 0x80200000
#define BL31_NOBITS_BASE 0x20058000
#define BL31_NOBITS_LIMIT 0x2006d000
#define BL31_RWDATA_BASE 0x2006d000
#define BL31_RWDATA_LIMIT 0x20070000
#define BL32_FDT_OVERLAY_ADDR 0x9d000000
#ifdef SPD_trusty
#define IMX_TRUSTY_STACK_SIZE 0x100
#endif
/* system memory map define */
#define DEVICE0_MAP MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW)
#define DEVICE1_MAP MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW)
/* Map partial DRAM space for DRAM low-power mode control */
#define DEVICE2_MAP MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW)
/* MU and FSB */
#define ELE_MAP MAP_REGION_FLAT(0x27010000, 0x20000, MT_DEVICE | MT_RW | MT_NS)
#define SEC_SIM_MAP MAP_REGION_FLAT(0x2802B000, 0x1000, MT_DEVICE | MT_RW | MT_NS) /* SEC SIM */
/* For SCMI shared memory region */
#define SRAM0_MAP MAP_REGION_FLAT(SRAM0_BASE, 0x1000, MT_RW | MT_DEVICE)
#endif /* PLATFORM_DEF_H */

View file

@ -0,0 +1,100 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IMX8_SCMI_H
#define IMX8_SCMI_H
#include <stdint.h>
#define SCMI_SHMEM_CHANNEL_ERROR BIT_32(1)
#define SCMI_SHMEM_CHANNEL_FREE BIT_32(0)
#define SCMI_SHMEM_FLAG_INTR_ENABLED BIT_32(0)
enum scmi_std_protocol {
SCMI_PROTOCOL_BASE = 0x10,
SCMI_PROTOCOL_POWER_DOMAIN = 0x11,
SCMI_PROTOCOL_SYS_POWER = 0x12,
SCMI_PROTOCOL_PERF_DOMAIN = 0x13,
SCMI_PROTOCOL_CLK = 0x14,
SCMI_PROTOCOL_SENSOR = 0x15,
SCMI_PROTOCOL_RESET_DOMAIN = 0x16,
};
#define MSG_ID(m) ((m) & 0xff)
#define MSG_TYPE(m) (((m) >> 8) & 0x3)
#define MSG_PRO_ID(m) (((m) >> 10) & 0xff)
#define MSG_TOKEN(m) (((m) >> 18) & 0x3ff)
enum {
SCMI_POWER_DOMAIN_PROTOCOL = 0x11,
SCMI_SYS_PWR_DOMAIN_PROTOCOL = 0x12,
SCMI_PER_DOMAIN_PROTOCOL = 0x13,
SCMI_CLK_DOMAIN_PROTOCOL = 0x14,
SCMI_SENSOR_PROTOCOL = 0x15,
};
#define PROTOCOL_VERSION 0
#define PROTOCOL_ATTRIBUTES 1
#define PROTOCOL_MESSAGE_ATTRIBUTES 2
#define BASE_DISCOVER_VENDOR 3
#define BASE_DISCOVER_SUB_VENDOR 4
#define BASE_DISCOVER_IMPLEMENTATION_VERSION 5
#define BASE_DISCOVER_LIST_PROTOCOLS 6
#define BASE_DISCOVER_AGENT 7
#define BASE_NOTIFY_ERRORS 8
#define BASE_SET_DEVICE_PERMISSIONS 9
#define BASE_SET_PROTOCOL_PERMISSIONS 0xA
#define BASE_RESET_AGENT_CONFIGURATION 0xB
enum {
SCMI_RET_SUCCESS = 0,
SCMI_RET_NOT_SUPPORTED = -1,
SCMI_RET_INVALID_PARAMETERS = -2,
SCMI_RET_DENIED = -3,
SCMI_RET_NOT_FOUND = -4,
SCMI_RET_OUT_OF_RANGE = -5,
SCMI_RET_BUSY = -6,
SCMI_RET_COMMS_ERROR = -7,
SCMI_RET_GENERIC_ERROR = -8,
SCMI_RET_HARDWARE_ERROR = -9,
SCMI_RET_PROTOCOL_ERROR = -10,
};
#define POWER_DOMAIN_ATTRIBUTES 3
#define POWER_DOMAIN_SUPPORT_NOTIFICATION BIT(31)
#define POWER_DOMAIN_SUPPORT_ASYNCHRONOUS BIT(30)
#define POWER_DOMAIN_SUPPORT_SYNCHRONOUS BIT(29)
#define POWER_STATE_SET 4
#define POWER_STATE_GET 5
#define POWER_STATE_NOTIFY 6
#define POWER_STATE_CHANGE_REQUESTED_NOTIFY 7
int scmi_power_domain_handler(uint32_t msg_id, void *shmem);
#define PERFORMANCE_DOMAIN_ATTRIBUTES 3
#define PERFORMANCE_DESCRIBE_LEVELS 4
#define PERFORMANCE_LIMITS_SET 5
#define PERFORMANCE_LIMITS_GET 6
#define PERFORMANCE_LEVEL_SET 7
#define PERFORMANCE_LEVEL_GET 8
#define PERFORMANCE_NOTIFY_LIMITS 9
#define PERFORMANCE_NOTIFY_LEVEL 0xA
#define PERFORMANCE_DESCRIBE_FAST_CHANNEL 0xB
int scmi_perf_domain_handler(uint32_t msg_id, void *shmem);
#define SENSOR_DESCRIPTION_GET 0x003
#define SENSOR_CONFIG_SET 0x004
#define SENSOR_TRIP_POINT_SET 0x005
#define SENSOR_READING_GET 0x006
int scmi_sensor_handler(uint32_t msg_id, void *shmem);
#define SMC_SHMEM_BASE 0x2201f000
#endif /* IMX8_SCMI_H */

View file

@ -0,0 +1,139 @@
/*
* Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Description:
* System Control and Management Interface (SCMI) support.
*/
#ifndef INTERNAL_SCMI_SENSOR_H
#define INTERNAL_SCMI_SENSOR_H
#include <stdint.h>
#define SCMI_PROTOCOL_VERSION_SENSOR UINT32_C(0x10000)
/*
* PROTOCOL_ATTRIBUTES
*/
struct scmi_sensor_protocol_attributes_p2a {
int32_t status;
uint32_t attributes;
uint32_t sensor_reg_address_low;
uint32_t sensor_reg_address_high;
uint32_t sensor_reg_len;
};
/*
* SENSOR_READING_GET
*/
#define SCMI_SENSOR_PROTOCOL_READING_GET_ASYNC_FLAG_MASK (1 << 0)
struct scmi_sensor_protocol_reading_get_a2p {
uint32_t sensor_id;
uint32_t flags;
};
struct scmi_sensor_protocol_reading_get_p2a {
int32_t status;
uint32_t sensor_value_low;
uint32_t sensor_value_high;
};
/*
* SENSOR_DESCRIPTION_GET
*/
#define SCMI_SENSOR_DESCS_MAX(MAILBOX_SIZE) \
((sizeof(struct scmi_sensor_protocol_description_get_p2a) < MAILBOX_SIZE) \
? ((MAILBOX_SIZE - \
sizeof(struct scmi_sensor_protocol_description_get_p2a)) \
/ sizeof(struct scmi_sensor_desc)) \
: 0)
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_POS 0
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_POS 11
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_POS 22
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_POS 27
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_MASK \
(UINT32_C(0xFF) << SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_POS)
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MASK \
(UINT32_C(0x1F) << SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_POS)
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MASK \
(UINT32_C(0x1F) << \
SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_POS)
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_MASK \
(UINT32_C(0x1F) << SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_POS)
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MAX \
(int32_t)(SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MASK >> 1)
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MIN \
(-(SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MAX + 1))
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MAX \
(int32_t)(SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_MASK >> 1)
#define SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MIN \
(-(SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MAX + 1))
#define SCMI_SENSOR_DESC_ATTRIBUTES_HIGH(SENSOR_TYPE, UNIT_MULTIPLIER, \
UPDATE_MULTIPLIER, UPDATE_INTERVAL) \
( \
(((SENSOR_TYPE) << \
SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_POS) & \
SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_TYPE_MASK) | \
(((UNIT_MULTIPLIER) << \
SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_POS) & \
SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UNIT_MULTIPLIER_MASK) | \
(((UPDATE_MULTIPLIER) << \
SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_POS) & \
SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_MULTIPLIER_MASK) | \
(((UPDATE_INTERVAL) << \
SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_POS) & \
SCMI_SENSOR_DESC_ATTRS_HIGH_SENSOR_UPDATE_INTERVAL_MASK) \
)
#define SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_POS 0
#define SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_POS 16
#define SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_MASK \
(UINT32_C(0xFFF) << SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_POS)
#define SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_MASK \
(UINT32_C(0xFFFF) << SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_POS)
#define SCMI_SENSOR_NUM_SENSOR_FLAGS(NUM_DESCS, NUM_REMAINING_DESCS) \
( \
(((NUM_DESCS) << \
SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_POS) & \
SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_DESCS_MASK) | \
(((NUM_REMAINING_DESCS) << \
SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_POS) & \
SCMI_SENSOR_NUM_SENSOR_FLAGS_NUM_REMAINING_DESCS_MASK) \
)
#define SCMI_SENSOR_NAME_LEN 16
struct scmi_sensor_desc {
uint32_t sensor_id;
uint32_t sensor_attributes_low;
uint32_t sensor_attributes_high;
char sensor_name[SCMI_SENSOR_NAME_LEN];
};
struct scmi_sensor_protocol_description_get_a2p {
uint32_t desc_index;
};
struct scmi_sensor_protocol_description_get_p2a {
int32_t status;
uint32_t num_sensor_flags;
struct scmi_sensor_desc sensor_desc[];
};
/* Event indices */
enum scmi_sensor_api_idx {
SCMI_SENSOR_EVENT_IDX_REQUEST,
SCMI_SENSOR_EVENT_IDX_COUNT,
};
#endif /* INTERNAL_SCMI_SENSOR_H */

View file

@ -0,0 +1,47 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IMX8ULP_XRDC_H
#define IMX8ULP_XRDC_H
#define DID_MAX 8
#define PAC_SLOT_ALL 128
#define MSC_SLOT_ALL 8
enum xrdc_mda_sa {
MDA_SA_S,
MDA_SA_NS,
MDA_SA_PT, /* pass through master's secure/nonsecure attribute */
};
struct xrdc_mda_config {
uint16_t mda_id;
uint16_t did;
enum xrdc_mda_sa sa;
};
struct xrdc_pac_msc_config {
uint16_t pac_msc_id;
uint16_t slot_id;
uint8_t dsel[DID_MAX];
};
struct xrdc_mrc_config {
uint16_t mrc_id;
uint16_t region_id;
uint32_t region_start;
uint32_t region_size;
uint8_t dsel[DID_MAX];
uint16_t accset[2];
};
/* APIs to apply and enable XRDC */
int xrdc_apply_lpav_config(void);
int xrdc_apply_hifi_config(void);
int xrdc_apply_apd_config(void);
void xrdc_enable(void);
#endif

View file

@ -0,0 +1,69 @@
#
# Copyright 2021-2024 NXP
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Translation tables library
include lib/xlat_tables_v2/xlat_tables.mk
# Include GICv3 driver files
include drivers/arm/gic/v3/gicv3.mk
PLAT_INCLUDES := -Iplat/imx/imx8ulp/include \
-Iplat/imx/common/include \
-Iplat/imx/imx8ulp/upower
IMX_GIC_SOURCES := ${GICV3_SOURCES} \
plat/common/plat_gicv3.c \
plat/common/plat_psci_common.c \
plat/imx/common/plat_imx8_gic.c
BL31_SOURCES += plat/imx/common/lpuart_console.S \
plat/imx/common/imx8_helpers.S \
plat/imx/imx8ulp/imx8ulp_bl31_setup.c \
plat/imx/imx8ulp/imx8ulp_psci.c \
plat/imx/imx8ulp/apd_context.c \
plat/imx/common/imx8_topology.c \
plat/imx/common/imx_sip_svc.c \
plat/imx/common/imx_sip_handler.c \
plat/imx/common/imx_bl31_common.c \
plat/common/plat_psci_common.c \
lib/cpus/aarch64/cortex_a35.S \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \
plat/imx/imx8ulp/xrdc/xrdc_core.c \
plat/imx/imx8ulp/imx8ulp_caam.c \
plat/imx/imx8ulp/dram.c \
drivers/scmi-msg/base.c \
drivers/scmi-msg/entry.c \
drivers/scmi-msg/smt.c \
drivers/scmi-msg/power_domain.c \
drivers/scmi-msg/sensor.c \
plat/imx/imx8ulp/scmi/scmi.c \
plat/imx/imx8ulp/scmi/scmi_pd.c \
plat/imx/imx8ulp/scmi/scmi_sensor.c \
plat/imx/imx8ulp/upower/upower_api.c \
plat/imx/imx8ulp/upower/upower_hal.c \
${XLAT_TABLES_LIB_SRCS} \
${IMX_GIC_SOURCES}
ifeq ($(findstring clang,$(notdir $(CC))),)
TF_CFLAGS_aarch64 += -fno-strict-aliasing
endif
USE_COHERENT_MEM := 1
RESET_TO_BL31 := 1
SEPARATE_NOBITS_REGION := 1
SEPARATE_RWDATA_REGION := 1
PROGRAMMABLE_RESET_ADDRESS := 1
COLD_BOOT_SINGLE_CPU := 1
WARMBOOT_ENABLE_DCACHE_EARLY := 1
BL32_BASE ?= 0xa6000000
BL32_SIZE ?= 0x2000000
$(eval $(call add_define,BL32_BASE))
$(eval $(call add_define,BL32_SIZE))
ifeq (${SPD},trusty)
BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1
endif

View file

@ -0,0 +1,69 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdint.h>
#include <drivers/scmi-msg.h>
#include <drivers/scmi.h>
#include <platform_def.h>
#define SMT_BUFFER_BASE 0x2201f000
#define SMT_BUFFER0_BASE SMT_BUFFER_BASE
#define SMT_BUFFER1_BASE (SMT_BUFFER_BASE + 0x200)
static struct scmi_msg_channel scmi_channel[] = {
[0] = {
.shm_addr = SMT_BUFFER0_BASE,
.shm_size = SMT_BUF_SLOT_SIZE,
},
};
struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id)
{
assert(agent_id < ARRAY_SIZE(scmi_channel));
return &scmi_channel[agent_id];
}
static const char vendor[] = "NXP";
static const char sub_vendor[] = "";
const char *plat_scmi_vendor_name(void)
{
return vendor;
}
const char *plat_scmi_sub_vendor_name(void)
{
return sub_vendor;
}
/* Currently supporting Clocks and Reset Domains */
static const uint8_t plat_protocol_list[] = {
SCMI_PROTOCOL_ID_POWER_DOMAIN,
SCMI_PROTOCOL_ID_SENSOR,
0U /* Null termination */
};
size_t plat_scmi_protocol_count(void)
{
return ARRAY_SIZE(plat_protocol_list) - 1U;
}
const uint8_t *plat_scmi_protocol_list(unsigned int agent_id __unused)
{
return plat_protocol_list;
}
void imx8ulp_init_scmi_server(void)
{
size_t i;
for (i = 0U; i < ARRAY_SIZE(scmi_channel); i++) {
scmi_smt_init_agent_channel(&scmi_channel[i]);
}
}

View file

@ -0,0 +1,371 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <inttypes.h>
#include <lib/libc/errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <common/debug.h>
#include <drivers/scmi.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <platform_def.h>
#include <scmi.h>
#include <upower_api.h>
#define POWER_STATE_ON (0 << 30)
#define POWER_STATE_OFF (1 << 30)
extern bool is_lpav_owned_by_apd(void);
enum {
PS0 = 0,
PS1 = 1,
PS2 = 2,
PS3 = 3,
PS4 = 4,
PS5 = 5,
PS6 = 6,
PS7 = 7,
PS8 = 8,
PS9 = 9,
PS10 = 10,
PS11 = 11,
PS12 = 12,
PS13 = 13,
PS14 = 14,
PS15 = 15,
PS16 = 16,
PS17 = 17,
PS18 = 18,
PS19 = 19,
};
#define SRAM_DMA1 BIT(6)
#define SRAM_FLEXSPI2 BIT(7)
#define SRAM_USB0 BIT(10)
#define SRAM_USDHC0 BIT(11)
#define SRAM_USDHC1 BIT(12)
#define SRAM_USDHC2_USB1 BIT(13)
#define SRAM_DCNANO GENMASK_32(18, 17)
#define SRAM_EPDC GENMASK_32(20, 19)
#define SRAM_DMA2 BIT(21)
#define SRAM_GPU2D GENMASK_32(23, 22)
#define SRAM_GPU3D GENMASK_32(25, 24)
#define SRAM_HIFI4 BIT(26)
#define SRAM_ISI_BUFFER BIT(27)
#define SRAM_MIPI_CSI_FIFO BIT(28)
#define SRAM_MIPI_DSI_FIFO BIT(29)
#define SRAM_PXP BIT(30)
#define SRAM_DMA0 BIT_64(33)
#define SRAM_FLEXCAN BIT_64(34)
#define SRAM_FLEXSPI0 BIT_64(35)
#define SRAM_FLEXSPI1 BIT_64(36)
struct psw {
char *name;
uint32_t reg;
int power_state;
uint32_t count;
int flags;
};
#define ALWAYS_ON BIT(0)
static struct psw imx8ulp_psw[] = {
[PS6] = { .name = "PS6", .reg = PS6, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON },
[PS7] = { .name = "PS7", .reg = PS7, .power_state = POWER_STATE_OFF },
[PS8] = { .name = "PS8", .reg = PS8, .power_state = POWER_STATE_OFF },
[PS13] = { .name = "PS13", .reg = PS13, .power_state = POWER_STATE_OFF },
[PS14] = { .name = "PS14", .reg = PS14, .flags = ALWAYS_ON, .power_state = POWER_STATE_OFF },
[PS15] = { .name = "PS15", .reg = PS15, .power_state = POWER_STATE_OFF },
[PS16] = { .name = "PS16", .reg = PS16, .flags = ALWAYS_ON, .power_state = POWER_STATE_ON },
};
struct power_domain {
char *name;
uint32_t reg;
uint32_t psw_parent;
uint32_t sram_parent;
uint64_t bits;
uint32_t power_state;
bool lpav; /* belong to lpav domain */
uint32_t sw_rst_reg; /* pcc sw reset reg offset */
};
/* The Rich OS need flow the macro */
#define IMX8ULP_PD_DMA1 0
#define IMX8ULP_PD_FLEXSPI2 1
#define IMX8ULP_PD_USB0 2
#define IMX8ULP_PD_USDHC0 3
#define IMX8ULP_PD_USDHC1 4
#define IMX8ULP_PD_USDHC2_USB1 5
#define IMX8ULP_PD_DCNANO 6
#define IMX8ULP_PD_EPDC 7
#define IMX8ULP_PD_DMA2 8
#define IMX8ULP_PD_GPU2D 9
#define IMX8ULP_PD_GPU3D 10
#define IMX8ULP_PD_HIFI4 11
#define IMX8ULP_PD_ISI 12
#define IMX8ULP_PD_MIPI_CSI 13
#define IMX8ULP_PD_MIPI_DSI 14
#define IMX8ULP_PD_PXP 15
#define IMX8ULP_PD_PS6 16
#define IMX8ULP_PD_PS7 17
#define IMX8ULP_PD_PS8 18
#define IMX8ULP_PD_PS13 19
#define IMX8ULP_PD_PS14 20
#define IMX8ULP_PD_PS15 21
#define IMX8ULP_PD_PS16 22
#define IMX8ULP_PD_MAX 23
/* LPAV peripheral PCC */
#define PCC_GPU2D (IMX_PCC5_BASE + 0xf0)
#define PCC_GPU3D (IMX_PCC5_BASE + 0xf4)
#define PCC_EPDC (IMX_PCC5_BASE + 0xcc)
#define PCC_CSI (IMX_PCC5_BASE + 0xbc)
#define PCC_PXP (IMX_PCC5_BASE + 0xd0)
#define PCC_SW_RST BIT(28)
#define PWR_DOMAIN(_name, _reg, _psw_parent, _sram_parent, \
_bits, _state, _lpav, _rst_reg) \
{ \
.name = _name, \
.reg = _reg, \
.psw_parent = _psw_parent, \
.sram_parent = _sram_parent, \
.bits = _bits, \
.power_state = _state, \
.lpav = _lpav, \
.sw_rst_reg = _rst_reg, \
}
static struct power_domain scmi_power_domains[] = {
PWR_DOMAIN("DMA1", IMX8ULP_PD_DMA1, PS6, PS6, SRAM_DMA1, POWER_STATE_OFF, false, 0U),
PWR_DOMAIN("FLEXSPI2", IMX8ULP_PD_FLEXSPI2, PS6, PS6, SRAM_FLEXSPI2, POWER_STATE_OFF, false, 0U),
PWR_DOMAIN("USB0", IMX8ULP_PD_USB0, PS6, PS6, SRAM_USB0, POWER_STATE_OFF, false, 0U),
PWR_DOMAIN("USDHC0", IMX8ULP_PD_USDHC0, PS6, PS6, SRAM_USDHC0, POWER_STATE_OFF, false, 0U),
PWR_DOMAIN("USDHC1", IMX8ULP_PD_USDHC1, PS6, PS6, SRAM_USDHC1, POWER_STATE_OFF, false, 0U),
PWR_DOMAIN("USDHC2_USB1", IMX8ULP_PD_USDHC2_USB1, PS6, PS6, SRAM_USDHC2_USB1, POWER_STATE_OFF, false, 0U),
PWR_DOMAIN("DCNano", IMX8ULP_PD_DCNANO, PS16, PS16, SRAM_DCNANO, POWER_STATE_OFF, true, 0U),
PWR_DOMAIN("EPDC", IMX8ULP_PD_EPDC, PS13, PS13, SRAM_EPDC, POWER_STATE_OFF, true, PCC_EPDC),
PWR_DOMAIN("DMA2", IMX8ULP_PD_DMA2, PS16, PS16, SRAM_DMA2, POWER_STATE_OFF, true, 0U),
PWR_DOMAIN("GPU2D", IMX8ULP_PD_GPU2D, PS16, PS16, SRAM_GPU2D, POWER_STATE_OFF, true, PCC_GPU2D),
PWR_DOMAIN("GPU3D", IMX8ULP_PD_GPU3D, PS7, PS7, SRAM_GPU3D, POWER_STATE_OFF, true, PCC_GPU3D),
PWR_DOMAIN("HIFI4", IMX8ULP_PD_HIFI4, PS8, PS8, SRAM_HIFI4, POWER_STATE_OFF, true, 0U),
PWR_DOMAIN("ISI", IMX8ULP_PD_ISI, PS16, PS16, SRAM_ISI_BUFFER, POWER_STATE_OFF, true, 0U),
PWR_DOMAIN("MIPI_CSI", IMX8ULP_PD_MIPI_CSI, PS15, PS16, SRAM_MIPI_CSI_FIFO, POWER_STATE_OFF, true, PCC_CSI),
PWR_DOMAIN("MIPI_DSI", IMX8ULP_PD_MIPI_DSI, PS14, PS16, SRAM_MIPI_DSI_FIFO, POWER_STATE_OFF, true, 0U),
PWR_DOMAIN("PXP", IMX8ULP_PD_PXP, PS13, PS13, SRAM_PXP | SRAM_EPDC, POWER_STATE_OFF, true, PCC_PXP)
};
size_t plat_scmi_pd_count(unsigned int agent_id __unused)
{
return ARRAY_SIZE(scmi_power_domains);
}
const char *plat_scmi_pd_get_name(unsigned int agent_id __unused,
unsigned int pd_id)
{
if (pd_id >= IMX8ULP_PD_PS6) {
return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].name;
}
return scmi_power_domains[pd_id].name;
}
unsigned int plat_scmi_pd_get_state(unsigned int agent_id __unused,
unsigned int pd_id __unused)
{
if (pd_id >= IMX8ULP_PD_PS6) {
return imx8ulp_psw[pd_id - IMX8ULP_PD_PS6].power_state;
}
return scmi_power_domains[pd_id].power_state;
}
extern void upower_wait_resp(void);
int upwr_pwm_power(const uint32_t swton[], const uint32_t memon[], bool on)
{
int ret_val;
int ret;
if (on == true) {
ret = upwr_pwm_power_on(swton, memon, NULL);
} else {
ret = upwr_pwm_power_off(swton, memon, NULL);
}
if (ret != 0U) {
WARN("%s failed: ret: %d, state: %x\n", __func__, ret, on);
return ret;
}
upower_wait_resp();
ret = upwr_poll_req_status(UPWR_SG_PWRMGMT, NULL, NULL, &ret_val, 1000);
if (ret != UPWR_REQ_OK) {
WARN("Failure %d, %s\n", ret, __func__);
if (ret == UPWR_REQ_BUSY) {
return -EBUSY;
} else {
return -EINVAL;
}
}
return 0;
}
int32_t plat_scmi_pd_psw(unsigned int index, unsigned int state)
{
uint32_t psw_parent = scmi_power_domains[index].psw_parent;
uint32_t sram_parent = scmi_power_domains[index].sram_parent;
uint64_t swt;
bool on;
int ret = 0;
if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) != 0U &&
(imx8ulp_psw[sram_parent].flags & ALWAYS_ON) != 0U) {
return 0;
}
on = (state == POWER_STATE_ON) ? true : false;
if ((imx8ulp_psw[psw_parent].flags & ALWAYS_ON) == 0U) {
swt = 1 << imx8ulp_psw[psw_parent].reg;
if (imx8ulp_psw[psw_parent].count == 0U) {
if (on == false) {
WARN("off PSW[%d] that already in off state\n", psw_parent);
ret = -EACCES;
} else {
ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
imx8ulp_psw[psw_parent].count++;
}
} else {
if (on == true) {
imx8ulp_psw[psw_parent].count++;
} else {
imx8ulp_psw[psw_parent].count--;
}
if (imx8ulp_psw[psw_parent].count == 0U) {
ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
}
}
}
if (!(imx8ulp_psw[sram_parent].flags & ALWAYS_ON) && (psw_parent != sram_parent)) {
swt = 1 << imx8ulp_psw[sram_parent].reg;
if (imx8ulp_psw[sram_parent].count == 0U) {
if (on == false) {
WARN("off PSW[%d] that already in off state\n", sram_parent);
ret = -EACCES;
} else {
ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
imx8ulp_psw[sram_parent].count++;
}
} else {
if (on == true) {
imx8ulp_psw[sram_parent].count++;
} else {
imx8ulp_psw[sram_parent].count--;
}
if (imx8ulp_psw[sram_parent].count == 0U) {
ret = upwr_pwm_power((const uint32_t *)&swt, NULL, on);
}
}
}
return ret;
}
bool pd_allow_power_off(unsigned int pd_id)
{
if (scmi_power_domains[pd_id].lpav) {
if (!is_lpav_owned_by_apd()) {
return false;
}
}
return true;
}
void assert_pcc_reset(unsigned int pcc)
{
/* if sw_rst_reg is valid, assert the pcc reset */
if (pcc != 0U) {
mmio_clrbits_32(pcc, PCC_SW_RST);
}
}
int32_t plat_scmi_pd_set_state(unsigned int agent_id __unused,
unsigned int flags,
unsigned int pd_id,
unsigned int state)
{
unsigned int ps_idx;
uint64_t mem;
bool on;
int ret;
if (flags != 0U || pd_id >= IMX8ULP_PD_PS6) {
return SCMI_NOT_SUPPORTED;
}
ps_idx = 0;
while (ps_idx < IMX8ULP_PD_PS6 && scmi_power_domains[ps_idx].reg != pd_id) {
ps_idx++;
}
if (ps_idx == IMX8ULP_PD_PS6) {
return SCMI_NOT_FOUND;
}
if (state == scmi_power_domains[ps_idx].power_state) {
return SCMI_SUCCESS;
}
mem = scmi_power_domains[ps_idx].bits;
on = (state == POWER_STATE_ON ? true : false);
if (on == true) {
/* Assert pcc sw reset if necessary */
assert_pcc_reset(scmi_power_domains[ps_idx].sw_rst_reg);
ret = plat_scmi_pd_psw(ps_idx, state);
if (ret != 0U) {
return SCMI_DENIED;
}
ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on);
if (ret != 0U) {
return SCMI_DENIED;
}
} else {
if (!pd_allow_power_off(ps_idx)) {
return SCMI_DENIED;
}
ret = upwr_pwm_power(NULL, (const uint32_t *)&mem, on);
if (ret != 0U) {
return SCMI_DENIED;
}
ret = plat_scmi_pd_psw(ps_idx, state);
if (ret != 0U) {
return SCMI_DENIED;
}
}
scmi_power_domains[pd_id].power_state = state;
return SCMI_SUCCESS;
}

View file

@ -0,0 +1,85 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <lib/libc/errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "../../../drivers/scmi-msg/sensor.h"
#include <common/debug.h>
#include <drivers/scmi.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <scmi.h>
#include <upower_api.h>
/* Only Temperature now */
static uint16_t imx_scmi_sensor_count(unsigned int agent_id __unused)
{
return 1U;
}
uint8_t imx_scmi_sensor_max_requests(unsigned int agent_id __unused)
{
return 1U;
}
extern int upower_read_temperature(uint32_t sensor_id, int32_t *temperature);
int imx_scmi_sensor_reading_get(uint32_t agent_id __unused, uint16_t sensor_id __unused,
uint32_t *val)
{
int32_t temperature;
int ret;
ret = upower_read_temperature(1, &temperature);
if (ret != 0U) {
val[0] = 0xFFFFFFFF;
} else {
val[0] = temperature;
}
val[1] = 0;
val[2] = 0;
val[3] = 0;
return ret;
}
#define SCMI_SENSOR_NAME_LENGTH_MAX 16U
uint32_t imx_scmi_sensor_state(uint32_t agent_id __unused, uint16_t sensor_id __unused)
{
return 1U;
}
uint32_t imx_scmi_sensor_description_get(uint32_t agent_id __unused, uint16_t desc_index __unused,
struct scmi_sensor_desc *desc __unused)
{
desc->id = 0;
desc->attr_low = 0;
desc->attr_high = 2;
strlcpy((char *)desc->name, "UPOWER-TEMP", 12);
desc->power = 0;
desc->resolution = 0;
desc->min_range_low = 0;
desc->min_range_high = 0x80000000;
desc->max_range_low = 0xffffffff;
desc->max_range_high = 0x7fffffff;
return 1U;
}
REGISTER_SCMI_SENSOR_OPS(imx_scmi_sensor_count,
imx_scmi_sensor_max_requests,
NULL,
imx_scmi_sensor_reading_get,
imx_scmi_sensor_description_get,
NULL,
imx_scmi_sensor_state,
NULL);

View file

@ -0,0 +1,279 @@
/*
* Copyright 2021-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MU_H
#define MU_H
#include <stdint.h>
typedef volatile unsigned int vuint32_t;
/****************************************************************************/
/* MODULE: Message Unit */
/****************************************************************************/
/* VER Register */
typedef union {
vuint32_t R;
struct {
vuint32_t FEATURE : 16;
vuint32_t MINOR : 8;
vuint32_t MAJOR : 8;
} B;
} MU_VER_t;
/* PAR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t TR_NUM : 8;
vuint32_t RR_NUM : 8;
vuint32_t GIR_NUM : 8;
vuint32_t FLAG_WIDTH : 8;
} B;
} MU_PAR_t;
/* CR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t MUR : 1;
vuint32_t MURIE : 1;
vuint32_t rsrv_1 : 30;
} B;
} MU_CR_t;
/* SR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t MURS : 1;
vuint32_t MURIP : 1;
vuint32_t EP : 1;
vuint32_t FUP : 1;
vuint32_t GIRP : 1;
vuint32_t TEP : 1;
vuint32_t RFP : 1;
vuint32_t CEP : 1;
vuint32_t rsrv_1 : 24;
} B;
} MU_SR_t;
/* CCR0 Register */
typedef union {
vuint32_t R;
struct {
vuint32_t NMI : 1;
vuint32_t HR : 1;
vuint32_t HRM : 1;
vuint32_t CLKE : 1;
vuint32_t RSTH : 1;
vuint32_t BOOT : 2;
vuint32_t rsrv_1 : 25;
} B;
} MU_CCR0_t;
/* CIER0 Register */
typedef union {
vuint32_t R;
struct {
vuint32_t rsrv_1 : 1;
vuint32_t HRIE : 1;
vuint32_t RUNIE : 1;
vuint32_t RAIE : 1;
vuint32_t HALTIE : 1;
vuint32_t WAITIE : 1;
vuint32_t STOPIE : 1;
vuint32_t PDIE : 1;
vuint32_t rsrv_2 : 24;
} B;
} MU_CIER0_t;
/* CSSR0 Register */
typedef union {
vuint32_t R;
struct {
vuint32_t NMIC : 1;
vuint32_t HRIP : 1;
vuint32_t RUN : 1;
vuint32_t RAIP : 1;
vuint32_t HALT : 1;
vuint32_t WAIT : 1;
vuint32_t STOP : 1;
vuint32_t PD : 1;
vuint32_t rsrv_1 : 24;
} B;
} MU_CSSR0_t;
/* CSR0 Register */
typedef union {
vuint32_t R;
struct {
vuint32_t rsrv_1 : 1;
vuint32_t HRIP : 1;
vuint32_t RUN : 1;
vuint32_t RAIP : 1;
vuint32_t HALT : 1;
vuint32_t WAIT : 1;
vuint32_t STOP : 1;
vuint32_t PD : 1;
vuint32_t rsrv_2 : 24;
} B;
} MU_CSR0_t;
/* FCR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t F0 : 1;
vuint32_t F1 : 1;
vuint32_t F2 : 1;
vuint32_t rsrv_1 : 29;
} B;
} MU_FCR_t;
/* FSR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t F0 : 1;
vuint32_t F1 : 1;
vuint32_t F2 : 1;
vuint32_t rsrv_1 : 29;
} B;
} MU_FSR_t;
/* GIER Register */
typedef union {
vuint32_t R;
struct {
vuint32_t GIE0 : 1;
vuint32_t GIE1 : 1;
vuint32_t rsrv_1 : 30;
} B;
} MU_GIER_t;
/* GCR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t GIR0 : 1;
vuint32_t GIR1 : 1;
vuint32_t rsrv_1 : 30;
} B;
} MU_GCR_t;
/* GSR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t GIP0 : 1;
vuint32_t GIP1 : 1;
vuint32_t rsrv_1 : 30;
} B;
} MU_GSR_t;
/* TCR Register */
typedef union{
vuint32_t R;
struct {
vuint32_t TIE0 : 1;
vuint32_t TIE1 : 1;
vuint32_t rsrv_1 : 30;
} B;
} MU_TCR_t;
/* TSR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t TE0 : 1;
vuint32_t TE1 : 1;
vuint32_t rsrv_1 : 30;
} B;
} MU_TSR_t;
/* RCR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t RIE0 : 1;
vuint32_t RIE1 : 1;
vuint32_t rsrv_1 : 30;
} B;
} MU_RCR_t;
/* RSR Register */
typedef union {
vuint32_t R;
struct {
vuint32_t RF0 : 1;
vuint32_t RF1 : 1;
vuint32_t rsrv_1 : 30;
} B;
} MU_RSR_t;
/* TR0 Register */
typedef union {
vuint32_t R;
struct {
vuint32_t TR_DATA : 32;
} B;
} MU_TR0_t;
/* TR1 Register */
typedef union {
vuint32_t R;
struct {
vuint32_t TR_DATA : 32;
} B;
} MU_TR1_t;
/* RR0 Register */
typedef union {
vuint32_t R;
struct {
vuint32_t RR_DATA : 32;
} B;
} MU_RR0_t;
/* RR1 Register */
typedef union {
vuint32_t R;
struct {
vuint32_t RR_DATA : 32;
} B;
} MU_RR1_t;
struct MU_t {
MU_VER_t VER;
MU_PAR_t PAR;
MU_CR_t CR;
MU_SR_t SR;
MU_CCR0_t CCR0;
MU_CIER0_t CIER0;
MU_CSSR0_t CSSR0;
MU_CSR0_t CSR0;
uint8_t MU_reserved0[224];
MU_FCR_t FCR;
MU_FSR_t FSR;
uint8_t MU_reserved1[8];
MU_GIER_t GIER;
MU_GCR_t GCR;
MU_GSR_t GSR;
uint8_t MU_reserved2[4];
MU_TCR_t TCR;
MU_TSR_t TSR;
MU_RCR_t RCR;
MU_RSR_t RSR;
uint8_t MU_reserved3[208];
MU_TR0_t TR[2];
uint8_t MU_reserved4[120];
MU_RR0_t RR[2];
};
#endif /* MU_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,742 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/**
* Copyright 2019-2024 NXP
*
* KEYWORDS: micro-power uPower driver API
* -----------------------------------------------------------------------------
* PURPOSE: uPower driver API #defines and typedefs shared with the firmware
* -----------------------------------------------------------------------------
* PARAMETERS:
* PARAM NAME RANGE:DESCRIPTION: DEFAULTS: UNITS
* -----------------------------------------------------------------------------
* REUSE ISSUES: no reuse issues
*/
#ifndef UPWR_DEFS_H
#define UPWR_DEFS_H
#include <stdint.h>
#ifndef UPWR_PMC_SWT_WORDS
#define UPWR_PMC_SWT_WORDS (1U)
#endif
#ifndef UPWR_PMC_MEM_WORDS
#define UPWR_PMC_MEM_WORDS (2U)
#endif
/* ****************************************************************************
* DOWNSTREAM MESSAGES - COMMANDS/FUNCTIONS
* ****************************************************************************
*/
#define UPWR_SRVGROUP_BITS (4U)
#define UPWR_FUNCTION_BITS (4U)
#define UPWR_PWDOMAIN_BITS (4U)
#define UPWR_HEADER_BITS \
(UPWR_SRVGROUP_BITS + UPWR_FUNCTION_BITS + UPWR_PWDOMAIN_BITS)
#define UPWR_ARG_BITS (32U - UPWR_HEADER_BITS)
#if ((UPWR_ARG_BITS & 1U) > 0U)
#error "UPWR_ARG_BITS must be an even number"
#endif
#define UPWR_ARG64_BITS (64U - UPWR_HEADER_BITS)
#define UPWR_HALF_ARG_BITS (UPWR_ARG_BITS >> 1U)
#define UPWR_DUAL_OFFSET_BITS ((UPWR_ARG_BITS + 32U) >> 1U)
/*
* message header: header fields common to all downstream messages.
*/
struct upwr_msg_hdr {
uint32_t domain : UPWR_PWDOMAIN_BITS; /* power domain */
uint32_t srvgrp : UPWR_SRVGROUP_BITS; /* service group */
uint32_t function : UPWR_FUNCTION_BITS; /* function */
uint32_t arg : UPWR_ARG_BITS; /* function-specific argument */
};
/* generic 1-word downstream message format */
typedef union {
struct upwr_msg_hdr hdr;
uint32_t word; /* message first word */
} upwr_down_1w_msg;
/* generic 2-word downstream message format */
typedef struct {
struct upwr_msg_hdr hdr;
uint32_t word2; /* message second word */
} upwr_down_2w_msg;
/* message format for functions that receive a pointer/offset */
typedef struct {
struct upwr_msg_hdr hdr;
uint32_t ptr; /* config struct offset */
} upwr_pointer_msg;
/* message format for functions that receive 2 pointers/offsets */
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint64_t rsv : UPWR_HEADER_BITS;
uint64_t ptr0 : UPWR_DUAL_OFFSET_BITS;
uint64_t ptr1 : UPWR_DUAL_OFFSET_BITS;
} ptrs;
} upwr_2pointer_msg;
#define UPWR_SG_EXCEPT (0U) /* 0 = exception */
#define UPWR_SG_PWRMGMT (1U) /* 1 = power management */
#define UPWR_SG_DELAYM (2U) /* 2 = delay measurement */
#define UPWR_SG_VOLTM (3U) /* 3 = voltage measurement */
#define UPWR_SG_CURRM (4U) /* 4 = current measurement */
#define UPWR_SG_TEMPM (5U) /* 5 = temperature measurement */
#define UPWR_SG_DIAG (6U) /* 6 = diagnostic */
#define UPWR_SG_COUNT (7U)
typedef uint32_t upwr_sg_t;
/* *************************************************************************
* Initialization - downstream
***************************************************************************/
typedef upwr_down_1w_msg upwr_start_msg; /* start command message */
typedef upwr_down_1w_msg upwr_power_on_msg; /* power on command message */
typedef upwr_down_1w_msg upwr_boot_start_msg; /* boot start command message */
typedef union {
struct upwr_msg_hdr hdr;
upwr_power_on_msg power_on;
upwr_boot_start_msg boot_start;
upwr_start_msg start;
} upwr_startup_down_msg;
/* *************************************************************************
* Service Group EXCEPTION - downstream
***************************************************************************/
#define UPWR_XCP_INIT (0U) /* 0 = init msg (not a service request itself) */
#define UPWR_XCP_PING (0U) /* 0 = also ping request, since its response isan init msg */
#define UPWR_XCP_START (1U) /* 1 = service start: upwr_start *(not a service request itself) */
#define UPWR_XCP_SHUTDOWN (2U) /* 2 = service shutdown: upwr_xcp_shutdown */
#define UPWR_XCP_CONFIG (3U) /* 3 = uPower configuration: upwr_xcp_config */
#define UPWR_XCP_SW_ALARM (4U) /* 4 = uPower software alarm: upwr_xcp_sw_alarm */
#define UPWR_XCP_I2C (5U) /* 5 = I2C access: upwr_xcp_i2c_access */
#define UPWR_XCP_SPARE_6 (6U) /* 6 = spare */
#define UPWR_XCP_SET_DDR_RETN (7U) /* 7 = set/clear ddr retention */
#define UPWR_XCP_SET_RTD_APD_LLWU (8U) /* 8 = set/clear rtd/apd llwu */
#define UPWR_XCP_SPARE_8 (8U) /* 8 = spare */
#define UPWR_XCP_SET_RTD_USE_DDR (9U) /* 9 = M33 core set it is using DDR or not */
#define UPWR_XCP_SPARE_9 (9U) /* 9 = spare */
#define UPWR_XCP_SPARE_10 (10U) /* 10 = spare */
#define UPWR_XCP_SET_MIPI_DSI_ENA (10U) /* 10 = set/clear mipi dsi ena */
#define UPWR_XCP_SPARE_11 (11U) /* 11 = spare */
#define UPWR_XCP_GET_MIPI_DSI_ENA (11U) /* 11 = get mipi dsi ena status */
#define UPWR_XCP_SPARE_12 (12U) /* 12 = spare */
#define UPWR_XCP_SET_OSC_MODE (12U) /* 12 = set uPower OSC mode, high or low */
#define UPWR_XCP_SPARE_13 (13U) /* 13 = spare */
#define UPWR_XCP_SPARE_14 (14U) /* 14 = spare */
#define UPWR_XCP_SPARE_15 (15U) /* 15 = spare */
#define UPWR_XCP_F_COUNT (16U)
typedef uint32_t upwr_xcp_f_t;
typedef upwr_down_1w_msg upwr_xcp_ping_msg;
typedef upwr_down_1w_msg upwr_xcp_shutdown_msg;
typedef upwr_power_on_msg upwr_xcp_power_on_msg;
typedef upwr_boot_start_msg upwr_xcp_boot_start_msg;
typedef upwr_start_msg upwr_xcp_start_msg;
typedef upwr_down_2w_msg upwr_xcp_config_msg;
typedef upwr_down_1w_msg upwr_xcp_swalarm_msg;
typedef upwr_down_1w_msg upwr_xcp_ddr_retn_msg;
typedef upwr_down_1w_msg upwr_xcp_set_mipi_dsi_ena_msg;
typedef upwr_down_1w_msg upwr_xcp_get_mipi_dsi_ena_msg;
typedef upwr_down_1w_msg upwr_xcp_rtd_use_ddr_msg;
typedef upwr_down_1w_msg upwr_xcp_rtd_apd_llwu_msg;
typedef upwr_down_1w_msg upwr_xcp_set_osc_mode_msg;
typedef upwr_pointer_msg upwr_xcp_i2c_msg;
/* structure pointed by message upwr_xcp_i2c_msg */
typedef struct {
uint16_t addr;
int8_t data_size;
uint8_t subaddr_size;
uint32_t subaddr;
uint32_t data;
} upwr_i2c_access;
/* Exception all messages */
typedef union {
struct upwr_msg_hdr hdr; /* message header */
upwr_xcp_ping_msg ping; /* ping */
upwr_xcp_start_msg start; /* service start */
upwr_xcp_shutdown_msg shutdown; /* shutdown */
upwr_xcp_boot_start_msg bootstart; /* boot start */
upwr_xcp_config_msg config; /* uPower configuration */
upwr_xcp_swalarm_msg swalarm; /* software alarm */
upwr_xcp_i2c_msg i2c; /* I2C access */
upwr_xcp_ddr_retn_msg set_ddr_retn; /* set ddr retention msg */
upwr_xcp_set_mipi_dsi_ena_msg set_mipi_dsi_ena; /* set mipi dsi ena msg */
upwr_xcp_get_mipi_dsi_ena_msg get_mipi_dsi_ena; /* get mipi dsi ena msg */
upwr_xcp_rtd_use_ddr_msg set_rtd_use_ddr; /* set rtd is using ddr msg */
upwr_xcp_rtd_apd_llwu_msg set_llwu; /* set rtd/apd llwu msg */
upwr_xcp_set_osc_mode_msg set_osc_mode; /* set osc_mode msg */
} upwr_xcp_msg;
/* structure pointed by message upwr_volt_dva_req_id_msg */
typedef struct {
uint32_t id_word0;
uint32_t id_word1;
uint32_t mode;
} upwr_dva_id_struct;
/**
* PMIC voltage accuracy is 12.5 mV, 12500 uV
*/
#define PMIC_VOLTAGE_MIN_STEP 12500U
/* *************************************************************************
* Service Group POWER MANAGEMENT - downstream
***************************************************************************/
#define UPWR_PWM_REGCFG (0U) /* 0 = regulator config: upwr_pwm_reg_config */
#define UPWR_PWM_DEVMODE (0U) /* deprecated, for old compile */
#define UPWR_PWM_VOLT (1U) /* 1 = voltage change: upwr_pwm_chng_reg_voltage */
#define UPWR_PWM_SWITCH (2U) /* 2 = switch control: upwr_pwm_chng_switch_mem */
#define UPWR_PWM_PWR_ON (3U) /* 3 = switch/RAM/ROM power on: upwr_pwm_power_on */
#define UPWR_PWM_PWR_OFF (4U) /* 4 = switch/RAM/ROM power off: upwr_pwm_power_off */
#define UPWR_PWM_RETAIN (5U) /* 5 = retain memory array: upwr_pwm_mem_retain */
#define UPWR_PWM_DOM_BIAS (6U) /* 6 = Domain bias control: upwr_pwm_chng_dom_bias */
#define UPWR_PWM_MEM_BIAS (7U) /* 7 = Memory bias control: upwr_pwm_chng_mem_bias */
#define UPWR_PWM_PMICCFG (8U) /* 8 = PMIC configuration: upwr_pwm_pmic_config */
#define UPWR_PWM_PMICMOD (8U) /* deprecated, for old compile */
#define UPWR_PWM_PES (9U) /* 9 so far, no use */
#define UPWR_PWM_CONFIG (10U) /* 10= apply power mode defined configuration */
#define UPWR_PWM_CFGPTR (11U) /* 11= configuration pointer */
#define UPWR_PWM_DOM_PWRON (12U) /* 12 = domain power on: upwr_pwm_dom_power_on */
#define UPWR_PWM_BOOT (13U) /* 13 = boot start: upwr_pwm_boot_start */
#define UPWR_PWM_FREQ (14U) /* 14 = domain frequency setup */
#define UPWR_PWM_PARAM (15U) /* 15 = power management parameters */
#define UPWR_PWM_F_COUNT (16U)
typedef uint32_t upwr_pwm_f_t;
#define MAX_PMETER_SSEL 7U
#define UPWR_VTM_CHNG_PMIC_RAIL_VOLT (0U) /* 0 = change pmic rail voltage */
#define UPWR_VTM_GET_PMIC_RAIL_VOLT (1U) /* 1 = get pmic rail voltage */
#define UPWR_VTM_PMIC_CONFIG (2U) /* 2 = configure PMIC IC */
#define UPWR_VTM_DVA_DUMP_INFO (3U) /* 3 = dump dva information */
#define UPWR_VTM_DVA_REQ_ID (4U) /* 4 = dva request ID array */
#define UPWR_VTM_DVA_REQ_DOMAIN (5U) /* 5 = dva request domain */
#define UPWR_VTM_DVA_REQ_SOC (6U) /* 6 = dva request the whole SOC */
#define UPWR_VTM_PMETER_MEAS (7U) /* 7 = pmeter measure */
#define UPWR_VTM_VMETER_MEAS (8U) /* 8 = vmeter measure */
#define UPWR_VTM_PMIC_COLD_RESET (9U) /* 9 = pmic cold reset */
#define UPWR_VTM_SET_DVFS_PMIC_RAIL (10U) /* 10 = set which domain use which pmic rail, for DVFS use */
#define UPWR_VTM_SET_PMIC_MODE (11U) /* 11 = set pmic mode */
#define UPWR_VTM_F_COUNT (16U)
typedef uint32_t upwr_volt_f_t;
#define VMETER_SEL_RTD 0U
#define VMETER_SEL_LDO 1U
#define VMETER_SEL_APD 2U
#define VMETER_SEL_AVD 3U
#define VMETER_SEL_MAX 3U
/**
* The total TSEL count is 256
*/
#define MAX_TEMP_TSEL 256U
/**
* Support 3 temperature sensor, sensor 0, 1, 2
*/
#define MAX_TEMP_SENSOR 2U
#define UPWR_TEMP_GET_CUR_TEMP (0U) /* 0 = get current temperature */
#define UPWR_TEMP_F_COUNT (1U)
typedef uint32_t upwr_temp_f_t;
#define UPWR_DMETER_GET_DELAY_MARGIN (0U) /* 0 = get delay margin */
#define UPWR_DMETER_SET_DELAY_MARGIN (1U) /* 1 = set delay margin */
#define UPWR_PMON_REQ (2U) /* 2 = process monitor service */
#define UPWR_DMETER_F_COUNT (3U)
typedef uint32_t upwr_dmeter_f_t;
typedef upwr_down_1w_msg upwr_volt_pmeter_meas_msg;
typedef upwr_down_1w_msg upwr_volt_pmic_set_mode_msg;
typedef upwr_down_1w_msg upwr_volt_vmeter_meas_msg;
struct upwr_reg_config_t {
uint32_t reg;
};
/* set of 32 switches */
struct upwr_switch_board_t {
uint32_t on; /* Switch on state,1 bit per instance */
uint32_t mask; /* actuation mask, 1 bit per instance */
};
/* set of 32 RAM/ROM switches */
struct upwr_mem_switches_t {
uint32_t array; /* RAM/ROM array state, 1 bit per instance */
uint32_t perif; /* RAM/ROM peripheral state, 1 bit per instance */
uint32_t mask; /* actuation mask, 1 bit per instance */
};
typedef upwr_down_1w_msg upwr_pwm_dom_pwron_msg; /* domain power on message */
typedef upwr_down_1w_msg upwr_pwm_boot_start_msg; /* boot start message */
/* functions with complex arguments use the pointer message formats: */
typedef upwr_pointer_msg upwr_pwm_retain_msg;
typedef upwr_pointer_msg upwr_pwm_pmode_cfg_msg;
#if (UPWR_ARG_BITS < UPWR_DOMBIAS_ARG_BITS)
#if ((UPWR_ARG_BITS + 32) < UPWR_DOMBIAS_ARG_BITS)
#error "too few message bits for domain bias argument"
#endif
#endif
/* service upwr_pwm_chng_dom_bias message argument fields */
#define UPWR_DOMBIAS_MODE_BITS (2U)
#define UPWR_DOMBIAS_RBB_BITS (8U)
#define UPWR_DOMBIAS_RSV_BITS (14U)
#define UPWR_DOMBIAS_ARG_BITS (UPWR_DOMBIAS_RSV_BITS + \
(2U * UPWR_DOMBIAS_MODE_BITS) + \
(4U * UPWR_DOMBIAS_RBB_BITS) + 2U)
/*
* upwr_pwm_dom_bias_args is an SoC-dependent message,
*/
typedef struct {
uint32_t: 12U; /* TODO: find a way to use UPWR_HEADER_BITS */
uint32_t dommode : UPWR_DOMBIAS_MODE_BITS;
uint32_t avdmode : UPWR_DOMBIAS_MODE_BITS;
uint32_t domapply : 1U;
uint32_t avdapply : 1U;
uint32_t rsv : UPWR_DOMBIAS_RSV_BITS;
uint32_t domrbbn : UPWR_DOMBIAS_RBB_BITS; /* RTD/APD back bias N-well */
uint32_t domrbbp : UPWR_DOMBIAS_RBB_BITS; /* RTD/APD back bias P-well */
uint32_t avdrbbn : UPWR_DOMBIAS_RBB_BITS; /* AVD back bias N-well */
uint32_t avdrbbp : UPWR_DOMBIAS_RBB_BITS; /* AVD back bias P-well */
} upwr_pwm_dom_bias_args;
typedef union {
struct upwr_msg_hdr hdr; /* message header */
struct {
upwr_pwm_dom_bias_args B;
} args;
} upwr_pwm_dom_bias_msg;
/* service upwr_pwm_chng_mem_bias message argument fields */
/*
* upwr_pwm_mem_bias_args is an SoC-dependent message,
* defined in upower_soc_defs.h
*/
typedef struct {
uint32_t: 12U; /* TODO: find a way to use UPWR_HEADER_BITS */
uint32_t en : 1U;
uint32_t rsv : 19U;
} upwr_pwm_mem_bias_args;
typedef union {
struct upwr_msg_hdr hdr; /* message header */
struct {
upwr_pwm_mem_bias_args B;
} args;
} upwr_pwm_mem_bias_msg;
typedef upwr_pointer_msg upwr_pwm_pes_seq_msg;
/* upwr_pwm_reg_config-specific message format */
typedef upwr_pointer_msg upwr_pwm_regcfg_msg;
/* upwr_volt_pmic_volt-specific message format */
typedef union {
struct upwr_msg_hdr hdr; /* message header */
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t domain : 8U;
uint32_t rail : 8U;
} args;
} upwr_volt_dom_pmic_rail_msg;
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t rail : 4U; /* pmic rail id */
uint32_t volt : 12U; /* voltage value, accurate to mV, support 0~3.3V */
} args;
} upwr_volt_pmic_set_volt_msg;
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t rail : 16U; /* pmic rail id */
} args;
} upwr_volt_pmic_get_volt_msg;
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv :UPWR_HEADER_BITS;
uint32_t domain : 8U;
uint32_t mode : 8U; /* work mode */
} args;
} upwr_volt_dva_req_domain_msg;
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t mode : 16U; /* work mode */
} args;
} upwr_volt_dva_req_soc_msg;
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t addr_offset : 16U; /* addr_offset to 0x28330000 */
} args;
} upwr_volt_dva_dump_info_msg;
typedef upwr_pointer_msg upwr_volt_pmiccfg_msg;
typedef upwr_pointer_msg upwr_volt_dva_req_id_msg;
typedef upwr_down_1w_msg upwr_volt_pmic_cold_reset_msg;
/* upwr_pwm_volt-specific message format */
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t reg : UPWR_HALF_ARG_BITS; /* regulator id */
uint32_t volt : UPWR_HALF_ARG_BITS; /* voltage value */
} args;
} upwr_pwm_volt_msg;
/* upwr_pwm_freq_setup-specific message format */
/**
* DVA adjust stage
*/
#define DVA_ADJUST_STAGE_INVALID 0U
/* first stage, gross adjust, for increase frequency use */
#define DVA_ADJUST_STAGE_ONE 1U
/* second stage, fine adjust for increase frequency use */
#define DVA_ADJUST_STAGE_TWO 2U
/* combine first + second stage, for descrese frequency use */
#define DVA_ADJUST_STAGE_FULL 3U
/**
* This message structure is used for DVFS feature
* 1. Because user may use different PMIC or different board,
* the pmic regulator of RTD/APD may change,
* so, user need to tell uPower the regulator number.
* The number must be matched with PMIC IC and board.
* use 4 bits for pmic regulator, support to 16 regulator.
*
* use 2 bits for DVA stage
*
* use 10 bits for target frequency, accurate to MHz, support to 1024 MHz
*/
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t rail : 4; /* pmic regulator */
uint32_t stage : 2; /* DVA stage */
uint32_t target_freq : 10; /* target frequency */
} args;
} upwr_pwm_freq_msg;
typedef upwr_down_2w_msg upwr_pwm_param_msg;
/* upwr_pwm_pmiccfg-specific message format */
typedef upwr_pointer_msg upwr_pwm_pmiccfg_msg;
/* functions that pass a pointer use message format upwr_pointer_msg */
typedef upwr_pointer_msg upwr_pwm_cfgptr_msg;
/* functions that pass 2 pointers use message format upwr_2pointer_msg
*/
typedef upwr_2pointer_msg upwr_pwm_switch_msg;
typedef upwr_2pointer_msg upwr_pwm_pwron_msg;
typedef upwr_2pointer_msg upwr_pwm_pwroff_msg;
/* Power Management all messages */
typedef union {
struct upwr_msg_hdr hdr; /* message header */
upwr_pwm_param_msg param; /* power management parameters */
upwr_pwm_dom_bias_msg dom_bias; /* domain bias message */
upwr_pwm_mem_bias_msg mem_bias; /* memory bias message */
upwr_pwm_pes_seq_msg pes; /* PE seq. message */
upwr_pwm_pmode_cfg_msg pmode; /* power mode config message */
upwr_pwm_regcfg_msg regcfg; /* regulator config message */
upwr_pwm_volt_msg volt; /* set voltage message */
upwr_pwm_freq_msg freq; /* set frequency message */
upwr_pwm_switch_msg switches; /* switch control message */
upwr_pwm_pwron_msg pwron; /* switch/RAM/ROM power on message */
upwr_pwm_pwroff_msg pwroff; /* switch/RAM/ROM power off message */
upwr_pwm_retain_msg retain; /* memory retain message */
upwr_pwm_cfgptr_msg cfgptr; /* configuration pointer message*/
upwr_pwm_dom_pwron_msg dompwron; /* domain power on message */
upwr_pwm_boot_start_msg boot; /* boot start message */
} upwr_pwm_msg;
typedef union {
struct upwr_msg_hdr hdr; /* message header */
upwr_volt_pmic_set_volt_msg set_pmic_volt; /* set pmic voltage message */
upwr_volt_pmic_get_volt_msg get_pmic_volt; /* set pmic voltage message */
upwr_volt_pmic_set_mode_msg set_pmic_mode; /* set pmic mode message */
upwr_volt_pmiccfg_msg pmiccfg; /* PMIC configuration message */
upwr_volt_dom_pmic_rail_msg dom_pmic_rail; /* domain bias message */
upwr_volt_dva_dump_info_msg dva_dump_info; /* dump dva info message */
upwr_volt_dva_req_id_msg dva_req_id; /* dump dva request id array message */
upwr_volt_dva_req_domain_msg dva_req_domain; /* dump dva request domain message */
upwr_volt_dva_req_soc_msg dva_req_soc; /* dump dva request whole soc message */
upwr_volt_pmeter_meas_msg pmeter_meas_msg; /* pmeter measure message */
upwr_volt_vmeter_meas_msg vmeter_meas_msg; /* vmeter measure message */
upwr_volt_pmic_cold_reset_msg cold_reset_msg; /* pmic cold reset message */
} upwr_volt_msg;
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t sensor_id : 16U; /* temperature sensor id */
} args;
} upwr_temp_get_cur_temp_msg;
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t index : 8U; /* the delay meter index */
uint32_t path : 8U; /* the critical path number */
} args;
} upwr_dmeter_get_delay_margin_msg;
#define MAX_DELAY_MARGIN 63U
#define MAX_DELAY_CRITICAL_PATH 7U
#define MAX_DELAY_METER_NUM 1U
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t index: 4U; /* the delay meter index */
uint32_t path: 4U; /* the critical path number */
uint32_t dm: 8U; /* the delay margin value of delay meter */
} args;
} upwr_dmeter_set_delay_margin_msg;
#define MAX_PMON_CHAIN_SEL 1U
typedef union {
struct upwr_msg_hdr hdr;
struct {
uint32_t rsv : UPWR_HEADER_BITS;
uint32_t chain_sel : 16U; /* the process monitor delay chain sel */
} args;
} upwr_pmon_msg;
typedef union {
struct upwr_msg_hdr hdr; /* message header */
upwr_temp_get_cur_temp_msg get_temp_msg; /* get current temperature message */
} upwr_temp_msg;
typedef union {
struct upwr_msg_hdr hdr; /* message header */
upwr_dmeter_get_delay_margin_msg get_margin_msg; /* get delay margin message */
upwr_dmeter_set_delay_margin_msg set_margin_msg; /* set delay margin message */
upwr_pmon_msg pmon_msg; /* process monitor message */
} upwr_dmeter_msg;
typedef upwr_down_2w_msg upwr_down_max_msg; /* longest downstream msg */
/*
* upwr_dom_bias_cfg_t and upwr_mem_bias_cfg_t are SoC-dependent structs,
* defined in upower_soc_defs.h
*/
/* Power and mem switches */
typedef struct {
volatile struct upwr_switch_board_t swt_board[UPWR_PMC_SWT_WORDS];
volatile struct upwr_mem_switches_t swt_mem[UPWR_PMC_MEM_WORDS];
} swt_config_t;
/* *************************************************************************
* Service Group DIAGNOSE - downstream
***************************************************************************/
/* Diagnose Functions */
#define UPWR_DGN_MODE (0U) /* 0 = diagnose mode: upwr_dgn_mode */
#define UPWR_DGN_F_COUNT (1U)
#define UPWR_DGN_BUFFER_EN (2U)
typedef uint32_t upwr_dgn_f_t;
#define UPWR_DGN_ALL2ERR (0U) /* record all until an error occurs, freeze recording on error */
#define UPWR_DGN_ALL2HLT (1U) /* record all until an error occurs, halt core on error */
#define UPWR_DGN_ALL (2U) /* trace, warnings, errors, task state recorded */
#define UPWR_DGN_MAX UPWR_DGN_ALL
#define UPWR_DGN_TRACE (3U) /* trace, warnings, errors recorded */
#define UPWR_DGN_SRVREQ (4U) /* service request activity recorded */
#define UPWR_DGN_WARN (5U) /* warnings and errors recorded */
#define UPWR_DGN_ERROR (6U) /* only errors recorded */
#define UPWR_DGN_NONE (7U) /* no diagnostic recorded */
#define UPWR_DGN_COUNT (8U)
typedef uint32_t upwr_dgn_mode_t;
typedef upwr_down_1w_msg upwr_dgn_mode_msg;
typedef union {
struct upwr_msg_hdr hdr;
upwr_dgn_mode_msg mode_msg;
} upwr_dgn_msg;
typedef struct {
struct upwr_msg_hdr hdr;
uint32_t buf_addr;
} upwr_dgn_v2_msg;
/* diagnostics log types in the shared RAM log buffer */
typedef enum {
DGN_LOG_NONE = 0x00000000,
DGN_LOG_INFO = 0x10000000,
DGN_LOG_ERROR = 0x20000000,
DGN_LOG_ASSERT = 0x30000000,
DGN_LOG_EXCEPT = 0x40000000,
DGN_LOG_EVENT = 0x50000000, // old event trace
DGN_LOG_EVENTNEW = 0x60000000, // new event trace
DGN_LOG_SERVICE = 0x70000000,
DGN_LOG_TASKDEF = 0x80000000,
DGN_LOG_TASKEXE = 0x90000000,
DGN_LOG_MUTEX = 0xA0000000,
DGN_LOG_SEMAPH = 0xB0000000,
DGN_LOG_TIMER = 0xC0000000,
DGN_LOG_CALLTRACE = 0xD0000000,
DGN_LOG_DATA = 0xE0000000,
DGN_LOG_PCTRACE = 0xF0000000
} upwr_dgn_log_t;
/* ****************************************************************************
* UPSTREAM MESSAGES - RESPONSES
* ****************************************************************************
*/
/* generic ok/ko response message */
#define UPWR_RESP_ERR_BITS (4U)
#define UPWR_RESP_HDR_BITS (UPWR_RESP_ERR_BITS+\
UPWR_SRVGROUP_BITS+UPWR_FUNCTION_BITS)
#define UPWR_RESP_RET_BITS (32U - UPWR_RESP_HDR_BITS)
#define UPWR_RESP_OK (0U) /* no error */
#define UPWR_RESP_SG_BUSY (1U) /* service group is busy */
#define UPWR_RESP_SHUTDOWN (2U) /* services not up or shutting down */
#define UPWR_RESP_BAD_REQ (3U) /* invalid request */
#define UPWR_RESP_BAD_STATE (4U) /* system state doesn't allow perform the request */
#define UPWR_RESP_UNINSTALLD (5U) /* service or function not installed */
#define UPWR_RESP_UNINSTALLED (5U) /* service or function not installed (alias) */
#define UPWR_RESP_RESOURCE (6U) /* resource not available */
#define UPWR_RESP_TIMEOUT (7U) /* service timeout */
#define UPWR_RESP_COUNT (8U)
typedef uint32_t upwr_resp_t;
struct upwr_resp_hdr {
uint32_t errcode : UPWR_RESP_ERR_BITS;
uint32_t srvgrp : UPWR_SRVGROUP_BITS; /* service group */
uint32_t function: UPWR_FUNCTION_BITS;
uint32_t ret : UPWR_RESP_RET_BITS; /* return value, if any */
};
/* generic 1-word upstream message format */
typedef union {
struct upwr_resp_hdr hdr;
uint32_t word;
} upwr_resp_msg;
/* generic 2-word upstream message format */
typedef struct {
struct upwr_resp_hdr hdr;
uint32_t word2; /* message second word */
} upwr_up_2w_msg;
typedef upwr_up_2w_msg upwr_up_max_msg;
/* *************************************************************************
* Exception/Initialization - upstream
***************************************************************************/
#define UPWR_SOC_BITS (7U)
#define UPWR_VMINOR_BITS (4U)
#define UPWR_VFIXES_BITS (4U)
#define UPWR_VMAJOR_BITS \
(32U - UPWR_HEADER_BITS - UPWR_SOC_BITS - UPWR_VMINOR_BITS - UPWR_VFIXES_BITS)
typedef struct {
uint32_t soc_id;
uint32_t vmajor;
uint32_t vminor;
uint32_t vfixes;
} upwr_code_vers_t;
/* message sent by firmware initialization, received by upwr_init */
typedef union {
struct upwr_resp_hdr hdr;
struct {
uint32_t rsv : UPWR_RESP_HDR_BITS;
uint32_t soc : UPWR_SOC_BITS; /* SoC identification */
uint32_t vmajor : UPWR_VMAJOR_BITS; /* firmware major version */
uint32_t vminor : UPWR_VMINOR_BITS; /* firmware minor version */
uint32_t vfixes : UPWR_VFIXES_BITS; /* firmware fixes version */
} args;
} upwr_init_msg;
/* message sent by firmware when the core platform is powered up */
typedef upwr_resp_msg upwr_power_up_msg;
/* message sent by firmware when the core reset is released for boot */
typedef upwr_resp_msg upwr_boot_up_msg;
/* message sent by firmware when ready for service requests */
#define UPWR_RAM_VMINOR_BITS (7)
#define UPWR_RAM_VFIXES_BITS (6)
#define UPWR_RAM_VMAJOR_BITS (32 - UPWR_HEADER_BITS \
- UPWR_RAM_VFIXES_BITS - UPWR_RAM_VMINOR_BITS)
typedef union {
struct upwr_resp_hdr hdr;
struct {
uint32_t rsv : UPWR_RESP_HDR_BITS;
uint32_t vmajor : UPWR_RAM_VMAJOR_BITS; /* RAM fw major version */
uint32_t vminor : UPWR_RAM_VMINOR_BITS; /* RAM fw minor version */
uint32_t vfixes : UPWR_RAM_VFIXES_BITS; /* RAM fw fixes version */
} args;
} upwr_ready_msg;
/* message sent by firmware when shutdown finishes */
typedef upwr_resp_msg upwr_shutdown_msg;
typedef union {
struct upwr_resp_hdr hdr;
upwr_init_msg init;
upwr_power_up_msg pwrup;
upwr_boot_up_msg booted;
upwr_ready_msg ready;
} upwr_startup_up_msg;
/* message sent by firmware for uPower config setting */
typedef upwr_resp_msg upwr_config_resp_msg;
/* message sent by firmware for uPower alarm */
typedef upwr_resp_msg upwr_alarm_resp_msg;
/* *************************************************************************
* Power Management - upstream
***************************************************************************/
typedef upwr_resp_msg upwr_param_resp_msg;
enum work_mode {
OVER_DRIVE,
NORMAL_DRIVE,
LOW_DRIVE
};
#define UTIMER3_MAX_COUNT 0xFFFFU
#endif /* UPWR_DEFS_H */

View file

@ -0,0 +1,201 @@
/*
* Copyright 2020-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include "upower_api.h"
#include "upower_defs.h"
#define UPOWER_AP_MU1_ADDR U(0x29280000)
struct MU_t *muptr = (struct MU_t *)UPOWER_AP_MU1_ADDR;
void upower_apd_inst_isr(upwr_isr_callb txrx_isr,
upwr_isr_callb excp_isr)
{
/* Do nothing */
}
int upower_status(int status)
{
int ret = -1;
switch (status) {
case 0:
VERBOSE("finished successfully!\n");
ret = 0;
break;
case -1:
VERBOSE("memory allocation or resource failed!\n");
break;
case -2:
VERBOSE("invalid argument!\n");
break;
case -3:
VERBOSE("called in an invalid API state!\n");
break;
default:
VERBOSE("invalid return status\n");
break;
}
return ret;
}
void upower_wait_resp(void)
{
while (muptr->RSR.B.RF0 == 0) {
udelay(100);
}
upwr_txrx_isr();
}
static void user_upwr_rdy_callb(uint32_t soc, uint32_t vmajor, uint32_t vminor)
{
NOTICE("%s: soc=%x\n", __func__, soc);
NOTICE("%s: RAM version:%d.%d\n", __func__, vmajor, vminor);
}
int upower_init(void)
{
int status;
status = upwr_init(APD_DOMAIN, muptr, NULL, NULL, upower_apd_inst_isr, NULL);
if (upower_status(status)) {
ERROR("%s: upower init failure\n", __func__);
return -EINVAL;
}
NOTICE("%s: start uPower RAM service\n", __func__);
status = upwr_start(1, user_upwr_rdy_callb);
upower_wait_resp();
/* poll status */
if (upower_status(status)) {
NOTICE("%s: upower init failure\n", __func__);
return status;
}
return 0;
}
int upower_pwm(int domain_id, bool pwr_on)
{
int ret, ret_val;
uint32_t swt;
if (domain_id == 9U || domain_id == 11U || domain_id == 12U) {
swt = BIT_32(12) | BIT_32(11) | BIT_32(10) | BIT_32(9);
} else {
swt = BIT_32(domain_id);
}
if (pwr_on) {
ret = upwr_pwm_power_on(&swt, NULL, NULL);
} else {
ret = upwr_pwm_power_off(&swt, NULL, NULL);
}
if (ret) {
NOTICE("%s failed: ret: %d, pwr_on: %d\n", __func__, ret, pwr_on);
return ret;
}
upower_wait_resp();
ret = upwr_poll_req_status(UPWR_SG_PWRMGMT, NULL, NULL, &ret_val, 1000);
if (ret != UPWR_REQ_OK) {
NOTICE("Failure %d, %s\n", ret, __func__);
if (ret == UPWR_REQ_BUSY) {
return -EBUSY;
} else {
return -EINVAL;
}
}
return 0;
}
int upower_read_temperature(uint32_t sensor_id, int32_t *temperature)
{
int ret, ret_val;
upwr_resp_t err_code;
int64_t t;
ret = upwr_tpm_get_temperature(sensor_id, NULL);
if (ret) {
return ret;
}
upower_wait_resp();
ret = upwr_poll_req_status(UPWR_SG_TEMPM, NULL, &err_code, &ret_val, 1000);
if (ret > UPWR_REQ_OK) {
return ret;
}
t = ret_val & 0xff;
*temperature = (2673049 * t * t * t / 10000000 + 3734262 * t * t / 100000 +
4487042 * t / 100 - 4698694) / 100000;
return 0;
}
int upower_pmic_i2c_write(uint32_t reg_addr, uint32_t reg_val)
{
int ret, ret_val;
upwr_resp_t err_code;
ret = upwr_xcp_i2c_access(0x32, 1, 1, reg_addr, reg_val, NULL);
if (ret) {
WARN("pmic i2c read failed ret %d\n", ret);
return ret;
}
upower_wait_resp();
ret = upwr_poll_req_status(UPWR_SG_EXCEPT, NULL, &err_code, &ret_val, 1000);
if (ret != UPWR_REQ_OK) {
WARN("i2c poll Failure %d, err_code %d, ret_val 0x%x\n",
ret, err_code, ret_val);
return ret;
}
VERBOSE("PMIC write reg[0x%x], val[0x%x]\n", reg_addr, reg_val);
return 0;
}
int upower_pmic_i2c_read(uint32_t reg_addr, uint32_t *reg_val)
{
int ret, ret_val;
upwr_resp_t err_code;
if (reg_val == NULL) {
return -1;
}
ret = upwr_xcp_i2c_access(0x32, -1, 1, reg_addr, 0, NULL);
if (ret) {
WARN("pmic i2c read failed ret %d\n", ret);
return ret;
}
upower_wait_resp();
ret = upwr_poll_req_status(UPWR_SG_EXCEPT, NULL, &err_code, &ret_val, 1000);
if (ret != UPWR_REQ_OK) {
WARN("i2c poll Failure %d, err_code %d, ret_val 0x%x\n",
ret, err_code, ret_val);
return ret;
}
*reg_val = ret_val;
VERBOSE("PMIC read reg[0x%x], val[0x%x]\n", reg_addr, *reg_val);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,134 @@
/*
* Copyright 2020-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <xrdc.h>
#define SP(X) ((X) << 9)
#define SU(X) ((X) << 6)
#define NP(X) ((X) << 3)
#define NU(X) ((X) << 0)
#define RWX 7
#define RW 6
#define R 4
#define X 1
struct xrdc_mda_config imx8ulp_mda[] = {
{ 0, 7, MDA_SA_PT }, /* A core */
{ 1, 1, MDA_SA_NS }, /* DMA1 */
{ 2, 1, MDA_SA_NS }, /* USB */
{ 3, 1, MDA_SA_NS }, /* PXP-> .M10 */
{ 4, 1, MDA_SA_NS }, /* ENET */
{ 5, 1, MDA_SA_PT }, /* CAAM */
{ 6, 1, MDA_SA_NS }, /* USDHC0 */
{ 7, 1, MDA_SA_NS }, /* USDHC1 */
{ 8, 1, MDA_SA_NS }, /* USDHC2 */
{ 9, 2, MDA_SA_NS }, /* HIFI4 */
{ 10, 3, MDA_SA_NS }, /* GPU3D */
{ 11, 3, MDA_SA_NS }, /* GPU2D */
{ 12, 3, MDA_SA_NS }, /* EPDC */
{ 13, 3, MDA_SA_NS }, /* DCNano */
{ 14, 3, MDA_SA_NS }, /* ISI */
{ 15, 3, MDA_SA_NS }, /* PXP->NIC_LPAV.M0 */
{ 16, 3, MDA_SA_NS }, /* DMA2 */
};
#ifdef SPD_opteed
#define TEE_SHM_SIZE 0x400000
#else
#define TEE_SHM_SIZE 0x0
#endif
#if defined(SPD_opteed) || defined(SPD_trusty)
#define DRAM_MEM_0_START (0x80000000)
#define DRAM_MEM_0_SIZE (BL32_BASE - 0x80000000)
#define DRAM_MEM_1_START (BL32_BASE)
#define DRAM_MEM_1_SIZE (BL32_SIZE - TEE_SHM_SIZE)
#ifndef SPD_trusty
#define DRAM_MEM_2_START (DRAM_MEM_1_START + DRAM_MEM_1_SIZE)
#define DRAM_MEM_2_SIZE (0x80000000 - DRAM_MEM_1_SIZE - DRAM_MEM_0_SIZE)
#else
#define SECURE_HEAP_START (0xA9600000)
#define SECURE_HEAP_SIZE (0x6000000)
#define DRAM_MEM_END (0x100000000)
#define DRAM_MEM_2_START (DRAM_MEM_1_START + DRAM_MEM_1_SIZE)
#define DRAM_MEM_2_SIZE (SECURE_HEAP_START - DRAM_MEM_2_START)
#define DRAM_MEM_3_START (DRAM_MEM_2_START + DRAM_MEM_2_SIZE)
#define DRAM_MEM_3_SIZE (SECURE_HEAP_SIZE)
#define DRAM_MEM_4_START (DRAM_MEM_3_START + DRAM_MEM_3_SIZE)
#define DRAM_MEM_4_SIZE (DRAM_MEM_END - DRAM_MEM_4_START)
#endif
#endif
struct xrdc_mrc_config imx8ulp_mrc[] = {
{ 0, 0, 0x0, 0x30000, {0, 0, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* ROM1 */
{ 1, 0, 0x60000000, 0x10000000, {1, 1, 0, 0, 1, 0, 1, 1}, {0xfff, 0} }, /* Flexspi2 */
{ 2, 0, 0x22020000, 0x40000, {1, 1, 0, 0, 1, 0, 1, 1}, {0xfff, 0} }, /* SRAM2 */
{ 3, 0, 0x22010000, 0x10000, {1, 1, 0, 0, 1, 0, 1, 1}, {0xfff, 0} }, /* SRAM0 */
#if defined(SPD_opteed) || defined(SPD_trusty)
{ 4, 0, DRAM_MEM_0_START, DRAM_MEM_0_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* DRAM for A35, DMA1, USDHC0*/
{ 4, 1, DRAM_MEM_1_START, DRAM_MEM_1_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfc0, 0} }, /* TEE DRAM for A35, DMA1, USDHC0*/
{ 4, 2, DRAM_MEM_2_START, DRAM_MEM_2_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* DRAM for A35, DMA1, USDHC0*/
#ifdef SPD_trusty
{ 4, 3, DRAM_MEM_3_START, DRAM_MEM_3_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfc0, 0} }, /* DRAM for A35, DMA1, USDHC0*/
{ 4, 4, DRAM_MEM_4_START, DRAM_MEM_4_SIZE, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* DRAM for A35, DMA1, USDHC0*/
#endif
{ 5, 0, DRAM_MEM_0_START, DRAM_MEM_0_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for NIC_PER */
{ 5, 1, DRAM_MEM_1_START, DRAM_MEM_1_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfc0, 0} }, /* TEE DRAM for NIC_PER */
{ 5, 2, DRAM_MEM_2_START, DRAM_MEM_2_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for NIC_PER */
#ifdef SPD_trusty
{ 5, 3, DRAM_MEM_3_START, DRAM_MEM_3_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfc0, 0} }, /* DRAM for NIC_PER */
{ 5, 4, DRAM_MEM_4_START, DRAM_MEM_4_SIZE, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for NIC_PER */
#endif
#ifdef SPD_trusty
{ 6, 0, DRAM_MEM_0_START, DRAM_MEM_0_SIZE, {1, 1, 0, 2, 1, 0, 1, 1}, {0xfff, 0x93f} }, /* DRAM for LPAV and RTD*/
{ 6, 1, DRAM_MEM_1_START, DRAM_MEM_1_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfc0, 0} }, /* TEE DRAM for LPAV and RTD*/
{ 6, 2, DRAM_MEM_2_START, DRAM_MEM_2_SIZE, {1, 1, 0, 2, 1, 0, 1, 1}, {0xfff, 0x93f} }, /* DRAM for LPAV and RTD*/
{ 6, 3, DRAM_MEM_3_START, DRAM_MEM_3_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfc0, 0} }, /* DRAM for LPAV and RTD*/
{ 6, 4, DRAM_MEM_4_START, DRAM_MEM_4_SIZE, {1, 1, 0, 2, 1, 0, 1, 1}, {0xfff, 0x93f} }, /* DRAM for LPAV and RTD*/
#else
{ 6, 0, DRAM_MEM_0_START, DRAM_MEM_0_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfff, 0} }, /* DRAM for LPAV and RTD*/
{ 6, 1, DRAM_MEM_1_START, DRAM_MEM_1_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfc0, 0} }, /* TEE DRAM for LPAV and RTD*/
{ 6, 2, DRAM_MEM_2_START, DRAM_MEM_2_SIZE, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfff, 0} }, /* DRAM for LPAV and RTD*/
#endif
#else
{ 4, 0, 0x80000000, 0x80000000, {0, 1, 0, 0, 0, 0, 0, 1}, {0xfff, 0} }, /* DRAM for A35, DMA1, USDHC0*/
{ 5, 0, 0x80000000, 0x80000000, {0, 1, 0, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for NIC_PER */
{ 6, 0, 0x80000000, 0x80000000, {1, 1, 0, 1, 1, 0, 1, 1}, {0xfff, 0} }, /* DRAM for LPAV and RTD*/
#endif
{ 7, 0, 0x80000000, 0x10000000, {0, 0, 1, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for HIFI4 */
{ 7, 1, 0x90000000, 0x10000000, {0, 0, 1, 0, 0, 0, 0, 0}, {0xfff, 0} }, /* DRAM for HIFI4 */
{ 8, 0, 0x21000000, 0x10000, {1, 1, 1, 1, 1, 0, 1, 1}, {0xfff, 0} }, /* SRAM1 */
{ 9, 0, 0x1ffc0000, 0xc0000, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0} }, /* SSRAM for HIFI4 */
{ 10, 0, 0x1ffc0000, 0xc0000, {0, 0, 0, 0, 0, 0, 0, 0}, {0, 0} }, /* SSRAM for LPAV */
{ 11, 0, 0x21170000, 0x10000, {0, 0, 1, 0, 0, 0, 0, 2}, {0xfff, SP(RW) | SU(RW) | NP(RW)} }, /* HIFI4 TCM */
{ 11, 1, 0x21180000, 0x10000, {0, 0, 1, 0, 0, 0, 0, 2}, {SP(RW) | SU(RW) | NP(RW) | NU(RW), SP(RW) | SU(RW) | NP(RW)} }, /* HIFI4 TCM */
{ 12, 0, 0x2d400000, 0x100000, {0, 0, 0, 0, 0, 0, 0, 1}, {SP(RW) | SU(RW) | NP(RW) | NU(RW), 0} }, /* GIC500 */
};
struct xrdc_pac_msc_config imx8ulp_pdac[] = {
{ 0, PAC_SLOT_ALL, {0, 7, 0, 0, 0, 0, 0, 7} }, /* PAC0 */
{ 0, 36, {0, 0, 0, 0, 0, 0, 7, 7} }, /* PAC0 slot 36 for CMC1 */
{ 0, 41, {0, 0, 0, 0, 0, 0, 7, 7} }, /* PAC0 slot 41 for SIM_AD */
{ 1, PAC_SLOT_ALL, {0, 7, 0, 0, 0, 0, 0, 7} }, /* PAC1 */
{ 1, 0, {0, 7, 0, 0, 0, 0, 7, 7} }, /* PAC1 slot 0 for PCC4 */
{ 1, 6, {0, 7, 7, 0, 0, 0, 0, 7} }, /* PAC1 slot 6 for LPUART6 */
{ 1, 9, {0, 7, 7, 7, 0, 0, 0, 7} }, /* SAI5 for HIFI4 and eDMA2 */
{ 1, 12, {0, 7, 0, 0, 0, 0, 7, 7} }, /* PAC1 slot 12 for IOMUXC1 */
{ 2, PAC_SLOT_ALL, {7, 7, 7, 7, 0, 0, 7, 7} }, /* PAC2 */
};
struct xrdc_pac_msc_config imx8ulp_msc[] = {
{ 0, 0, {0, 0, 0, 0, 0, 0, 7, 7} }, /* MSC0 GPIOE */
{ 0, 1, {0, 0, 0, 0, 0, 0, 7, 7} }, /* MSC0 GPIOF */
{ 1, MSC_SLOT_ALL, {0, 0, 0, 0, 0, 0, 7, 7} }, /* MSC1 GPIOD */
{ 2, MSC_SLOT_ALL, {0, 0, 0, 0, 0, 0, 7, 7} }, /* MSC2 GPU3D/2D/DCNANO/DDR registers */
};

View file

@ -0,0 +1,327 @@
/*
* Copyright 2020-2024 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include "xrdc_config.h"
#define XRDC_ADDR 0x292f0000
#define MRC_OFFSET 0x2000
#define MRC_STEP 0x200
#define XRDC_MGR_PAC_ID U(0)
#define XRDC_MGR_PAC_SLOT U(47)
enum xrdc_comp_type {
MDA_TYPE = (1 << 16),
MRC_TYPE = (2 << 16),
PAC_TYPE = (3 << 16),
MSC_TYPE = (4 << 16),
};
enum xrdc_pd_type {
XRDC_AD_PD,
XRDC_HIFI_PD,
XRDC_AV_PD,
};
#define XRDC_TYPE_MASK (0x7 << 16)
#define XRDC_ID_MASK 0xFFFF
#define XRDC_ID(id) ((id) & XRDC_ID_MASK)
typedef bool (*xrdc_check_func)(enum xrdc_comp_type type, uint16_t id);
/* Access below XRDC needs enable PS 8
* and HIFI clocks and release HIFI firstly
*/
uint32_t hifi_xrdc_list[] = {
(MDA_TYPE | XRDC_ID(9)),
(MRC_TYPE | XRDC_ID(7)),
(MRC_TYPE | XRDC_ID(9)),
(MRC_TYPE | XRDC_ID(11)),
};
/* Access below XRDC needs enable PS 16 firstly */
uint32_t av_periph_xrdc_list[] = {
(MDA_TYPE | XRDC_ID(10)),
(MDA_TYPE | XRDC_ID(11)),
(MDA_TYPE | XRDC_ID(12)),
(MDA_TYPE | XRDC_ID(13)),
(MDA_TYPE | XRDC_ID(14)),
(MDA_TYPE | XRDC_ID(15)),
(MDA_TYPE | XRDC_ID(16)),
(PAC_TYPE | XRDC_ID(2)),
(MRC_TYPE | XRDC_ID(6)),
(MRC_TYPE | XRDC_ID(8)),
(MRC_TYPE | XRDC_ID(10)),
(MSC_TYPE | XRDC_ID(1)),
(MSC_TYPE | XRDC_ID(2)),
};
uint32_t imx8ulp_pac_slots[] = {
61, 23, 53
};
uint32_t imx8ulp_msc_slots[] = {
2, 1, 7
};
static int xrdc_config_mrc_w0_w1(uint32_t mrc_con, uint32_t region, uint32_t w0, uint32_t size)
{
uint32_t w0_addr, w1_addr;
w0_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20;
w1_addr = w0_addr + 4;
if ((size % 32) != 0) {
return -EINVAL;
}
mmio_write_32(w0_addr, w0 & ~0x1f);
mmio_write_32(w1_addr, w0 + size - 1);
return 0;
}
static int xrdc_config_mrc_w2(uint32_t mrc_con, uint32_t region, uint32_t dxsel_all)
{
uint32_t w2_addr;
w2_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0x8;
mmio_write_32(w2_addr, dxsel_all);
return 0;
}
static int xrdc_config_mrc_w3_w4(uint32_t mrc_con, uint32_t region, uint32_t w3, uint32_t w4)
{
uint32_t w3_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0xC;
uint32_t w4_addr = w3_addr + 4;
mmio_write_32(w3_addr, w3);
mmio_write_32(w4_addr, w4);
return 0;
}
static int xrdc_config_pac(uint32_t pac, uint32_t index, uint32_t dxacp)
{
uint32_t w0_addr;
uint32_t val;
if (pac > 2U) {
return -EINVAL;
}
/* Skip the PAC slot for XRDC MGR, use Sentinel configuration */
if (pac == XRDC_MGR_PAC_ID && index == XRDC_MGR_PAC_SLOT) {
return 0;
}
w0_addr = XRDC_ADDR + 0x1000 + 0x400 * pac + 0x8 * index;
mmio_write_32(w0_addr, dxacp);
val = mmio_read_32(w0_addr + 4);
mmio_write_32(w0_addr + 4, val | BIT_32(31));
return 0;
}
static int xrdc_config_msc(uint32_t msc, uint32_t index, uint32_t dxacp)
{
uint32_t w0_addr;
uint32_t val;
if (msc > 2) {
return -EINVAL;
}
w0_addr = XRDC_ADDR + 0x4000 + 0x400 * msc + 0x8 * index;
mmio_write_32(w0_addr, dxacp);
val = mmio_read_32(w0_addr + 4);
mmio_write_32(w0_addr + 4, val | BIT_32(31));
return 0;
}
static int xrdc_config_mda(uint32_t mda_con, uint32_t dom, enum xrdc_mda_sa sa)
{
uint32_t w0_addr;
uint32_t val;
w0_addr = XRDC_ADDR + 0x800 + mda_con * 0x20;
val = mmio_read_32(w0_addr);
if (val & BIT_32(29)) {
mmio_write_32(w0_addr, (val & (~0xFF)) | dom |
BIT_32(31) | 0x20 | ((sa & 0x3) << 6));
} else {
mmio_write_32(w0_addr, dom | BIT_32(31));
mmio_write_32(w0_addr + 0x4, dom | BIT_32(31));
}
return 0;
}
static bool xrdc_check_pd(enum xrdc_comp_type type,
uint16_t id, enum xrdc_pd_type pd)
{
unsigned int i, size;
uint32_t item = type | XRDC_ID(id);
uint32_t *list;
if (pd == XRDC_HIFI_PD) {
size = ARRAY_SIZE(hifi_xrdc_list);
list = hifi_xrdc_list;
} else if (pd == XRDC_AV_PD) {
size = ARRAY_SIZE(av_periph_xrdc_list);
list = av_periph_xrdc_list;
} else {
return false;
}
for (i = 0U; i < size; i++) {
if (item == list[i]) {
return true;
}
}
return false;
}
static bool xrdc_check_lpav(enum xrdc_comp_type type, uint16_t id)
{
return xrdc_check_pd(type, id, XRDC_AV_PD);
}
static bool xrdc_check_hifi(enum xrdc_comp_type type, uint16_t id)
{
return xrdc_check_pd(type, id, XRDC_HIFI_PD);
}
static bool xrdc_check_ad(enum xrdc_comp_type type, uint16_t id)
{
return (!xrdc_check_pd(type, id, XRDC_HIFI_PD) &&
!xrdc_check_pd(type, id, XRDC_AV_PD));
}
static int xrdc_apply_config(xrdc_check_func check_func)
{
unsigned int i, j;
uint32_t val;
for (i = 0U; i < ARRAY_SIZE(imx8ulp_mda); i++) {
if (check_func(MDA_TYPE, imx8ulp_mda[i].mda_id)) {
xrdc_config_mda(imx8ulp_mda[i].mda_id,
imx8ulp_mda[i].did, imx8ulp_mda[i].sa);
}
}
for (i = 0U; i < ARRAY_SIZE(imx8ulp_mrc); i++) {
if (check_func(MRC_TYPE, imx8ulp_mrc[i].mrc_id)) {
xrdc_config_mrc_w0_w1(imx8ulp_mrc[i].mrc_id,
imx8ulp_mrc[i].region_id,
imx8ulp_mrc[i].region_start,
imx8ulp_mrc[i].region_size);
val = 0;
for (j = 0U; j < DID_MAX; j++) {
val |= imx8ulp_mrc[i].dsel[j] << (3 * j);
}
xrdc_config_mrc_w2(imx8ulp_mrc[i].mrc_id, imx8ulp_mrc[i].region_id, val);
xrdc_config_mrc_w3_w4(imx8ulp_mrc[i].mrc_id, imx8ulp_mrc[i].region_id,
0, imx8ulp_mrc[i].accset[0] | (imx8ulp_mrc[i].accset[1] << 16) | BIT_32(31));
}
}
for (i = 0U; i < ARRAY_SIZE(imx8ulp_pdac); i++) {
if (check_func(PAC_TYPE, imx8ulp_pdac[i].pac_msc_id)) {
val = 0;
for (j = 0U; j < DID_MAX; j++) {
val |= imx8ulp_pdac[i].dsel[j] << (3 * j);
}
if (imx8ulp_pdac[i].slot_id == PAC_SLOT_ALL) {
/* Apply to all slots*/
for (j = 0U; j < imx8ulp_pac_slots[imx8ulp_pdac[i].pac_msc_id]; j++) {
xrdc_config_pac(imx8ulp_pdac[i].pac_msc_id, j, val);
}
} else {
if (imx8ulp_pdac[i].slot_id >= imx8ulp_pac_slots[imx8ulp_pdac[i].pac_msc_id]) {
return -EINVAL;
}
xrdc_config_pac(imx8ulp_pdac[i].pac_msc_id, imx8ulp_pdac[i].slot_id, val);
}
}
}
for (i = 0U; i < ARRAY_SIZE(imx8ulp_msc); i++) {
if (check_func(MSC_TYPE, imx8ulp_msc[i].pac_msc_id)) {
val = 0;
for (j = 0U; j < DID_MAX; j++) {
val |= imx8ulp_msc[i].dsel[j] << (3 * j);
}
if (imx8ulp_msc[i].slot_id == MSC_SLOT_ALL) {
/* Apply to all slots*/
for (j = 0U; j < imx8ulp_msc_slots[imx8ulp_msc[i].pac_msc_id]; j++) {
xrdc_config_msc(imx8ulp_msc[i].pac_msc_id, j, val);
}
} else {
if (imx8ulp_msc[i].slot_id >= imx8ulp_msc_slots[imx8ulp_msc[i].pac_msc_id]) {
return -EINVAL;
}
xrdc_config_msc(imx8ulp_msc[i].pac_msc_id, imx8ulp_msc[i].slot_id, val);
}
}
}
return 0;
}
int xrdc_apply_lpav_config(void)
{
/* Configure PAC2 to allow to access PCC5 */
xrdc_config_pac(2, 39, 0xe00000);
/* Enable the eDMA2 MP clock for MDA16 access */
mmio_write_32(IMX_PCC5_BASE + 0x0, 0xc0000000);
return xrdc_apply_config(xrdc_check_lpav);
}
int xrdc_apply_hifi_config(void)
{
return xrdc_apply_config(xrdc_check_hifi);
}
int xrdc_apply_apd_config(void)
{
return xrdc_apply_config(xrdc_check_ad);
}
void xrdc_enable(void)
{
mmio_write_32(XRDC_ADDR, BIT(14) | BIT(15) | BIT(0));
}