mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-15 17:14:21 +00:00
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:
commit
1c408d3c40
37 changed files with 11442 additions and 4 deletions
|
@ -413,6 +413,9 @@ subsections:
|
|||
- title: i.MX 8
|
||||
scope: imx8
|
||||
|
||||
- title: i.MX 8ULP
|
||||
scope: imx8ulp
|
||||
|
||||
- title: i.MX 9
|
||||
scope: imx9
|
||||
|
||||
|
|
|
@ -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
69
docs/plat/imx8ulp.rst
Normal 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 NXP’s 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
|
||||
|
|
@ -27,6 +27,7 @@ Platform Ports
|
|||
warp7
|
||||
imx8
|
||||
imx8m
|
||||
imx8ulp
|
||||
imx9
|
||||
npcm845x
|
||||
nxp/index
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
277
drivers/scmi-msg/sensor.c
Normal 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
125
drivers/scmi-msg/sensor.h
Normal 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 */
|
|
@ -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.
|
||||
* ---------------------------------------------
|
||||
|
|
23
plat/imx/common/imx_bl31_common.c
Normal file
23
plat/imx/common/imx_bl31_common.c
Normal 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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
16
plat/imx/common/include/imx_plat_common.h
Normal file
16
plat/imx/common/include/imx_plat_common.h
Normal 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 */
|
|
@ -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__ */
|
||||
|
|
657
plat/imx/imx8ulp/apd_context.c
Normal file
657
plat/imx/imx8ulp/apd_context.c
Normal 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
798
plat/imx/imx8ulp/dram.c
Normal 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;
|
||||
}
|
186
plat/imx/imx8ulp/imx8ulp_bl31_setup.c
Normal file
186
plat/imx/imx8ulp/imx8ulp_bl31_setup.c
Normal 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
|
18
plat/imx/imx8ulp/imx8ulp_caam.c
Normal file
18
plat/imx/imx8ulp/imx8ulp_caam.c
Normal 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);
|
||||
}
|
555
plat/imx/imx8ulp/imx8ulp_psci.c
Normal file
555
plat/imx/imx8ulp/imx8ulp_psci.c
Normal 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;
|
||||
}
|
13
plat/imx/imx8ulp/include/dram.h
Normal file
13
plat/imx/imx8ulp/include/dram.h
Normal 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 */
|
||||
|
24
plat/imx/imx8ulp/include/imx8ulp_caam.h
Normal file
24
plat/imx/imx8ulp/include/imx8ulp_caam.h
Normal 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 */
|
124
plat/imx/imx8ulp/include/platform_def.h
Normal file
124
plat/imx/imx8ulp/include/platform_def.h
Normal 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 */
|
100
plat/imx/imx8ulp/include/scmi.h
Normal file
100
plat/imx/imx8ulp/include/scmi.h
Normal 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 */
|
139
plat/imx/imx8ulp/include/scmi_sensor.h
Normal file
139
plat/imx/imx8ulp/include/scmi_sensor.h
Normal 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 */
|
47
plat/imx/imx8ulp/include/xrdc.h
Normal file
47
plat/imx/imx8ulp/include/xrdc.h
Normal 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
|
69
plat/imx/imx8ulp/platform.mk
Normal file
69
plat/imx/imx8ulp/platform.mk
Normal 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
|
69
plat/imx/imx8ulp/scmi/scmi.c
Normal file
69
plat/imx/imx8ulp/scmi/scmi.c
Normal 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]);
|
||||
}
|
||||
}
|
371
plat/imx/imx8ulp/scmi/scmi_pd.c
Normal file
371
plat/imx/imx8ulp/scmi/scmi_pd.c
Normal 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;
|
||||
}
|
85
plat/imx/imx8ulp/scmi/scmi_sensor.c
Normal file
85
plat/imx/imx8ulp/scmi/scmi_sensor.c
Normal 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);
|
279
plat/imx/imx8ulp/upower/upmu.h
Normal file
279
plat/imx/imx8ulp/upower/upmu.h
Normal 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 */
|
3095
plat/imx/imx8ulp/upower/upower_api.c
Normal file
3095
plat/imx/imx8ulp/upower/upower_api.c
Normal file
File diff suppressed because it is too large
Load diff
1629
plat/imx/imx8ulp/upower/upower_api.h
Normal file
1629
plat/imx/imx8ulp/upower/upower_api.h
Normal file
File diff suppressed because it is too large
Load diff
742
plat/imx/imx8ulp/upower/upower_defs.h
Normal file
742
plat/imx/imx8ulp/upower/upower_defs.h
Normal 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 */
|
201
plat/imx/imx8ulp/upower/upower_hal.c
Normal file
201
plat/imx/imx8ulp/upower/upower_hal.c
Normal 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;
|
||||
}
|
1154
plat/imx/imx8ulp/upower/upower_soc_defs.h
Normal file
1154
plat/imx/imx8ulp/upower/upower_soc_defs.h
Normal file
File diff suppressed because it is too large
Load diff
134
plat/imx/imx8ulp/xrdc/xrdc_config.h
Normal file
134
plat/imx/imx8ulp/xrdc/xrdc_config.h
Normal 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 */
|
||||
};
|
327
plat/imx/imx8ulp/xrdc/xrdc_core.c
Normal file
327
plat/imx/imx8ulp/xrdc/xrdc_core.c
Normal 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));
|
||||
}
|
Loading…
Add table
Reference in a new issue