Commit 5d787dd9 authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #569 from Xilinx/zynqmp-v1

Support for Xilinx Zynq UltraScale+ MPSoC
parents af984eef 498256ed
/*
* Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bakery_lock.h>
#include <mmio.h>
#include <platform.h>
#include <arch_helpers.h>
#include "pm_ipi.h"
#include "../zynqmp_private.h"
/* IPI message buffers */
#define IPI_BUFFER_BASEADDR 0xFF990000U
#define IPI_BUFFER_RPU_0_BASE (IPI_BUFFER_BASEADDR + 0x0U)
#define IPI_BUFFER_RPU_1_BASE (IPI_BUFFER_BASEADDR + 0x200U)
#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
#define IPI_BUFFER_PL_0_BASE (IPI_BUFFER_BASEADDR + 0x600U)
#define IPI_BUFFER_PL_1_BASE (IPI_BUFFER_BASEADDR + 0x800U)
#define IPI_BUFFER_PL_2_BASE (IPI_BUFFER_BASEADDR + 0xA00U)
#define IPI_BUFFER_PL_3_BASE (IPI_BUFFER_BASEADDR + 0xC00U)
#define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U)
#define IPI_BUFFER_TARGET_RPU_0_OFFSET 0x0U
#define IPI_BUFFER_TARGET_RPU_1_OFFSET 0x40U
#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U
#define IPI_BUFFER_TARGET_PL_0_OFFSET 0xC0U
#define IPI_BUFFER_TARGET_PL_1_OFFSET 0x100U
#define IPI_BUFFER_TARGET_PL_2_OFFSET 0x140U
#define IPI_BUFFER_TARGET_PL_3_OFFSET 0x180U
#define IPI_BUFFER_TARGET_PMU_OFFSET 0x1C0U
#define IPI_BUFFER_REQ_OFFSET 0x0U
#define IPI_BUFFER_RESP_OFFSET 0x20U
/* IPI Base Address */
#define IPI_BASEADDR 0XFF300000
/* APU's IPI registers */
#define IPI_APU_ISR (IPI_BASEADDR + 0X00000010)
#define IPI_APU_IER (IPI_BASEADDR + 0X00000018)
#define IPI_APU_IDR (IPI_BASEADDR + 0X0000001C)
#define IPI_APU_ISR_PMU_0_MASK 0X00010000
#define IPI_APU_IER_PMU_0_MASK 0X00010000
#define IPI_TRIG_OFFSET 0
#define IPI_OBS_OFFSET 4
/* Power Management IPI interrupt number */
#define PM_INT_NUM 0
#define IPI_PMU_PM_INT_BASE (IPI_PMU_0_TRIG + (PM_INT_NUM * 0x1000))
#define IPI_PMU_PM_INT_MASK (IPI_APU_ISR_PMU_0_MASK << PM_INT_NUM)
#if (PM_INT_NUM < 0 || PM_INT_NUM > 3)
#error PM_INT_NUM value out of range
#endif
#define IPI_APU_MASK 1U
static bakery_lock_t pm_secure_lock;
const struct pm_ipi apu_ipi = {
.mask = IPI_APU_MASK,
.base = IPI_BASEADDR,
.buffer_base = IPI_BUFFER_APU_BASE,
};
/**
* pm_ipi_init() - Initialize IPI peripheral for communication with PMU
*
* @return On success, the initialization function must return 0.
* Any other return value will cause the framework to ignore
* the service
*
* Enable interrupts at registered entrance in IPI peripheral
* Called from pm_setup initialization function
*/
int pm_ipi_init(void)
{
bakery_lock_init(&pm_secure_lock);
/* IPI Interrupts Clear & Disable */
mmio_write_32(IPI_APU_ISR, 0xffffffff);
mmio_write_32(IPI_APU_IDR, 0xffffffff);
return 0;
}
/**
* pm_ipi_wait() - wait for pmu to handle request
* @proc proc which is waiting for PMU to handle request
*/
static enum pm_ret_status pm_ipi_wait(const struct pm_proc *proc)
{
int status;
/* Wait until previous interrupt is handled by PMU */
do {
status = mmio_read_32(proc->ipi->base + IPI_OBS_OFFSET) &
IPI_PMU_PM_INT_MASK;
/* TODO: 1) Use timer to add delay between read attempts */
/* TODO: 2) Return PM_RET_ERR_TIMEOUT if this times out */
} while (status);
return PM_RET_SUCCESS;
}
/**
* pm_ipi_send_common() - Sends IPI request to the PMU
* @proc Pointer to the processor who is initiating request
* @payload API id and call arguments to be written in IPI buffer
*
* Send an IPI request to the power controller. Caller needs to hold
* the 'pm_secure_lock' lock.
*
* @return Returns status, either success or error+reason
*/
static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT])
{
unsigned int offset = 0;
uintptr_t buffer_base = proc->ipi->buffer_base +
IPI_BUFFER_TARGET_PMU_OFFSET +
IPI_BUFFER_REQ_OFFSET;
/* Wait until previous interrupt is handled by PMU */
pm_ipi_wait(proc);
/* Write payload into IPI buffer */
for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
mmio_write_32(buffer_base + offset, payload[i]);
offset += PAYLOAD_ARG_SIZE;
}
/* Generate IPI to PMU */
mmio_write_32(proc->ipi->base + IPI_TRIG_OFFSET, IPI_PMU_PM_INT_MASK);
return PM_RET_SUCCESS;
}
/**
* pm_ipi_send() - Sends IPI request to the PMU
* @proc Pointer to the processor who is initiating request
* @payload API id and call arguments to be written in IPI buffer
*
* Send an IPI request to the power controller.
*
* @return Returns status, either success or error+reason
*/
enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT])
{
enum pm_ret_status ret;
bakery_lock_get(&pm_secure_lock);
ret = pm_ipi_send_common(proc, payload);
bakery_lock_release(&pm_secure_lock);
return ret;
}
/**
* pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt
* @proc Pointer to the processor who is waiting and reading response
* @value Used to return value from 2nd IPI buffer element (optional)
*
* @return Returns status, either success or error+reason
*/
static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
unsigned int *value)
{
uintptr_t buffer_base = proc->ipi->buffer_base +
IPI_BUFFER_TARGET_PMU_OFFSET +
IPI_BUFFER_RESP_OFFSET;
pm_ipi_wait(proc);
/*
* Read response from IPI buffer
* buf-0: success or error+reason
* buf-1: value
* buf-2: unused
* buf-3: unused
*/
if (value != NULL)
*value = mmio_read_32(buffer_base + PAYLOAD_ARG_SIZE);
return mmio_read_32(buffer_base);
}
/**
* pm_ipi_send_sync() - Sends IPI request to the PMU
* @proc Pointer to the processor who is initiating request
* @payload API id and call arguments to be written in IPI buffer
* @value Used to return value from 2nd IPI buffer element (optional)
*
* Send an IPI request to the power controller and wait for it to be handled.
*
* @return Returns status, either success or error+reason and, optionally,
* @value
*/
enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT],
unsigned int *value)
{
enum pm_ret_status ret;
bakery_lock_get(&pm_secure_lock);
ret = pm_ipi_send_common(proc, payload);
if (ret != PM_RET_SUCCESS)
goto unlock;
ret = pm_ipi_buff_read(proc, value);
unlock:
bakery_lock_release(&pm_secure_lock);
return ret;
}
/*
* Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _PM_IPI_H_
#define _PM_IPI_H_
#include "pm_common.h"
int pm_ipi_init(void);
enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT]);
enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
uint32_t payload[PAYLOAD_ARG_CNT],
unsigned int *value);
#endif /* _PM_IPI_H_ */
/*
* Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Top-level SMC handler for ZynqMP power management calls and
* IPI setup functions for communication with PMU.
*/
#include <errno.h>
#include <gic_common.h>
#include <runtime_svc.h>
#include <string.h>
#include "pm_api_sys.h"
#include "pm_client.h"
#include "pm_ipi.h"
#include "../zynqmp_private.h"
/* 0 - UP, !0 - DOWN */
static int32_t pm_down = !0;
/**
* pm_context - Structure which contains data for power management
* @api_version version of PM API, must match with one on PMU side
* @payload payload array used to store received
* data from ipi buffer registers
*/
static struct {
uint32_t api_version;
uint32_t payload[PAYLOAD_ARG_CNT];
} pm_ctx;
/**
* pm_setup() - PM service setup
*
* @return On success, the initialization function must return 0.
* Any other return value will cause the framework to ignore
* the service
*
* Initialization functions for ZynqMP power management for
* communicaton with PMU.
*
* Called from sip_svc_setup initialization function with the
* rt_svc_init signature.
*
*/
int pm_setup(void)
{
int status;
if (!zynqmp_is_pmu_up())
return -ENODEV;
status = pm_ipi_init();
if (status == 0)
INFO("BL31: PM Service Init Complete: API v%d.%d\n",
PM_VERSION_MAJOR, PM_VERSION_MINOR);
else
INFO("BL31: PM Service Init Failed, Error Code %d!\n", status);
pm_down = status;
return status;
}
/**
* pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
* @smc_fid - Function Identifier
* @x1 - x4 - Arguments
* @cookie - Unused
* @handler - Pointer to caller's context structure
*
* @return - Unused
*
* Determines that smc_fid is valid and supported PM SMC Function ID from the
* list of pm_api_ids, otherwise completes the request with
* the unknown SMC Function ID
*
* The SMC calls for PM service are forwarded from SIP Service SMC handler
* function with rt_svc_handle signature
*/
uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, void *cookie, void *handle, uint64_t flags)
{
enum pm_ret_status ret;
uint32_t pm_arg[4];
/* Handle case where PM wasn't initialized properly */
if (pm_down)
SMC_RET1(handle, SMC_UNK);
pm_arg[0] = (uint32_t)x1;
pm_arg[1] = (uint32_t)(x1 >> 32);
pm_arg[2] = (uint32_t)x2;
pm_arg[3] = (uint32_t)(x2 >> 32);
switch (smc_fid & FUNCID_NUM_MASK) {
/* PM API Functions */
case PM_SELF_SUSPEND:
ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_REQ_SUSPEND:
ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_REQ_WAKEUP:
ret = pm_req_wakeup(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_FORCE_POWERDOWN:
ret = pm_force_powerdown(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_ABORT_SUSPEND:
ret = pm_abort_suspend(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_SET_WAKEUP_SOURCE:
ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]);
SMC_RET1(handle, (uint64_t)ret);
case PM_SYSTEM_SHUTDOWN:
ret = pm_system_shutdown(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_REQ_NODE:
ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_RELEASE_NODE:
ret = pm_release_node(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_SET_REQUIREMENT:
ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_SET_MAX_LATENCY:
ret = pm_set_max_latency(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_GET_API_VERSION:
/* Check is PM API version already verified */
if (pm_ctx.api_version == PM_VERSION)
SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
((uint64_t)PM_VERSION << 32));
ret = pm_get_api_version(&pm_ctx.api_version);
SMC_RET1(handle, (uint64_t)ret |
((uint64_t)pm_ctx.api_version << 32));
case PM_SET_CONFIGURATION:
ret = pm_set_configuration(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_GET_NODE_STATUS:
ret = pm_get_node_status(pm_arg[0]);
SMC_RET1(handle, (uint64_t)ret);
case PM_GET_OP_CHARACTERISTIC:
ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_REGISTER_NOTIFIER:
ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2],
pm_arg[3]);
SMC_RET1(handle, (uint64_t)ret);
case PM_RESET_ASSERT:
ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
SMC_RET1(handle, (uint64_t)ret);
case PM_RESET_GET_STATUS:
{
uint32_t reset_status;
ret = pm_reset_get_status(pm_arg[0], &reset_status);
SMC_RET1(handle, (uint64_t)ret |
((uint64_t)reset_status << 32));
}
/* PM memory access functions */
case PM_MMIO_WRITE:
ret = pm_mmio_write(pm_arg[0], pm_arg[1], pm_arg[2]);
SMC_RET1(handle, (uint64_t)ret);
case PM_MMIO_READ:
{
uint32_t value;
ret = pm_mmio_read(pm_arg[0], &value);
SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
}
default:
WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
}
}
/*
* Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _PM_SVC_MAIN_H_
#define _PM_SVC_MAIN_H_
#include "pm_common.h"
int pm_setup(void);
uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
uint64_t x4, void *cookie, void *handle,
uint64_t flags);
#endif /* _PM_SVC_MAIN_H_ */
/*
* Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */
#include <runtime_svc.h>
#include <uuid.h>
#include "pm_svc_main.h"
/* SMC function IDs for SiP Service queries */
#define ZYNQMP_SIP_SVC_CALL_COUNT 0x8200ff00
#define ZYNQMP_SIP_SVC_UID 0x8200ff01
#define ZYNQMP_SIP_SVC_VERSION 0x8200ff03
/* SiP Service Calls version numbers */
#define SIP_SVC_VERSION_MAJOR 0
#define SIP_SVC_VERSION_MINOR 1
/* These macros are used to identify PM calls from the SMC function ID */
#define PM_FID_MASK 0xf000u
#define PM_FID_VALUE 0u
#define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
/* SiP Service UUID */
DEFINE_SVC_UUID(zynqmp_sip_uuid,
0x2a1d9b5c, 0x8605, 0x4023, 0xa6, 0x1b,
0xb9, 0x25, 0x82, 0x2d, 0xe3, 0xa5);
/**
* sip_svc_setup() - Setup SiP Service
*
* Invokes PM setup
*/
static int32_t sip_svc_setup(void)
{
/* PM implementation as SiP Service */
pm_setup();
return 0;
}
/**
* sip_svc_smc_handler() - Top-level SiP Service SMC handler
*
* Handler for all SiP SMC calls. Handles standard SIP requests
* and calls PM SMC handler if the call is for a PM-API function.
*/
uint64_t sip_svc_smc_handler(uint32_t smc_fid,
uint64_t x1,
uint64_t x2,
uint64_t x3,
uint64_t x4,
void *cookie,
void *handle,
uint64_t flags)
{
/* Let PM SMC handler deal with PM-related requests */
if (is_pm_fid(smc_fid)) {
return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
flags);
}
switch (smc_fid) {
case ZYNQMP_SIP_SVC_CALL_COUNT:
/* PM functions + default functions */
SMC_RET1(handle, PM_API_MAX + 2);
case ZYNQMP_SIP_SVC_UID:
SMC_UUID_RET(handle, zynqmp_sip_uuid);
case ZYNQMP_SIP_SVC_VERSION:
SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR);
default:
WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
}
}
/* Register PM Service Calls as runtime service */
DECLARE_RT_SVC(
sip_svc,
OEN_SIP_START,
OEN_SIP_END,
SMC_TYPE_FAST,
sip_svc_setup,
sip_svc_smc_handler);
# Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# Neither the name of ARM nor the names of its contributors may be used
# to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# TSP source files specific to ZynqMP platform
BL32_SOURCES += plat/common/aarch64/platform_mp_stack.S \
plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
/*
* Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bl_common.h>
#include <console.h>
#include <debug.h>
#include <platform_tsp.h>
#include <xlat_tables.h>
#include <plat_arm.h>
#include "../zynqmp_def.h"
#include "../zynqmp_private.h"
/*
* The next 3 constants identify the extents of the code & RO data region and
* the limit of the BL32 image. These addresses are used by the MMU setup code
* and therefore they must be page-aligned. It is the responsibility of the
* linker script to ensure that __RO_START__, __RO_END__ & & __BL32_END__
* linker symbols refer to page-aligned addresses.
*/
#define BL32_RO_BASE (unsigned long)(&__RO_START__)
#define BL32_RO_LIMIT (unsigned long)(&__RO_END__)
#define BL32_END (unsigned long)(&__BL32_END__)
#if USE_COHERENT_MEM
/*
* The next 2 constants identify the extents of the coherent memory region.
* These addresses are used by the MMU setup code and therefore they must be
* page-aligned. It is the responsibility of the linker script to ensure that
* __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
* page-aligned addresses.
*/
#define BL32_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
#define BL32_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
#endif
/*******************************************************************************
* Initialize the UART
******************************************************************************/
void tsp_early_platform_setup(void)
{
/*
* Initialize a different console than already in use to display
* messages from TSP
*/
console_init(ZYNQMP_UART0_BASE, zynqmp_get_uart_clk(),
ZYNQMP_UART_BAUDRATE);
/* Initialize the platform config for future decision making */
zynqmp_config_setup();
}
/*******************************************************************************
* Perform platform specific setup placeholder
******************************************************************************/
void tsp_platform_setup(void)
{
plat_arm_gic_driver_init();
plat_arm_gic_init();
}
/*******************************************************************************
* Perform the very early platform specific architectural setup here. At the
* moment this is only intializes the MMU
******************************************************************************/
void tsp_plat_arch_setup(void)
{
arm_configure_mmu_el1(BL32_RO_BASE,
(BL32_END - BL32_RO_BASE),
BL32_RO_BASE,
BL32_RO_LIMIT
#if USE_COHERENT_MEM
, BL32_COHERENT_RAM_BASE,
BL32_COHERENT_RAM_LIMIT
#endif
);
}
/*
* Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ZYNQMP_DEF_H__
#define __ZYNQMP_DEF_H__
#include <common_def.h>
/* Firmware Image Package */
#define ZYNQMP_PRIMARY_CPU 0
/* Memory location options for Shared data and TSP in ZYNQMP */
#define ZYNQMP_IN_TRUSTED_SRAM 0
#define ZYNQMP_IN_TRUSTED_DRAM 1
/*******************************************************************************
* ZYNQMP memory map related constants
******************************************************************************/
#define ZYNQMP_TRUSTED_SRAM_BASE 0xFFFC0000
#define ZYNQMP_TRUSTED_SRAM_SIZE 0x00040000
#define ZYNQMP_TRUSTED_SRAM_LIMIT (ZYNQMP_TRUSTED_SRAM_BASE + \
ZYNQMP_TRUSTED_SRAM_SIZE)
/* Location of trusted dram on the base zynqmp */
#define ZYNQMP_TRUSTED_DRAM_BASE 0x30000000 /* Can't overlap TZROM area */
#define ZYNQMP_TRUSTED_DRAM_SIZE 0x10000000
#define ZYNQMP_TRUSTED_DRAM_LIMIT (ZYNQMP_TRUSTED_DRAM_BASE + \
ZYNQMP_TRUSTED_DRAM_SIZE)
/* Aggregate of all devices in the first GB */
#define DEVICE0_BASE 0xFF000000
#define DEVICE0_SIZE 0x00E00000
#define DEVICE1_BASE 0xF9000000
#define DEVICE1_SIZE 0x01000000
/* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/
#define CRF_APB_BASE 0xFD1A0000
#define CRF_APB_SIZE 0x00600000
/* CRF registers and bitfields */
#define CRF_APB_RST_FPD_APU (CRF_APB_BASE + 0X00000104)
#define CRF_APB_RST_FPD_APU_ACPU_RESET (1 << 0)
#define CRF_APB_RST_FPD_APU_ACPU_PWRON_RESET (1 << 10)
/* CRL registers and bitfields */
#define CRL_APB_BASE 0xFF5E0000
#define CRL_APB_RPLL_CTRL (CRL_APB_BASE + 0x30)
#define CRL_APB_TIMESTAMP_REF_CTRL (CRL_APB_BASE + 0x128)
#define CRL_APB_RESET_CTRL (CRL_APB_BASE + 0x218)
#define CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1 << 24)
#define CRL_APB_RPLL_CTRL_BYPASS (1 << 3)
#define CRL_APB_RESET_CTRL_SOFT_RESET (1 << 4)
/* system counter registers and bitfields */
#define IOU_SCNTRS_BASE 0xFF260000
#define IOU_SCNTRS_CONTROL (IOU_SCNTRS_BASE + 0)
#define IOU_SCNTRS_BASEFREQ (IOU_SCNTRS_BASE + 0x20)
#define IOU_SCNTRS_CONTROL_EN (1 << 0)
/* APU registers and bitfields */
#define APU_BASE 0xFD5C0000
#define APU_CONFIG_0 (APU_BASE + 0x20)
#define APU_RVBAR_L_0 (APU_BASE + 0x40)
#define APU_RVBAR_H_0 (APU_BASE + 0x44)
#define APU_PWRCTL (APU_BASE + 0x90)
#define APU_CONFIG_0_VINITHI_SHIFT 8
#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1
#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2
#define APU_2_PWRCTL_CPUPWRDWNREQ_MASK 4
#define APU_3_PWRCTL_CPUPWRDWNREQ_MASK 8
/* PMU registers and bitfields */
#define PMU_GLOBAL_BASE 0xFFD80000
#define PMU_GLOBAL_CNTRL (PMU_GLOBAL_BASE + 0)
#define PMU_GLOBAL_REQ_PWRUP_STATUS (PMU_GLOBAL_BASE + 0x110)
#define PMU_GLOBAL_REQ_PWRUP_EN (PMU_GLOBAL_BASE + 0x118)
#define PMU_GLOBAL_REQ_PWRUP_DIS (PMU_GLOBAL_BASE + 0x11c)
#define PMU_GLOBAL_REQ_PWRUP_TRIG (PMU_GLOBAL_BASE + 0x120)
#define PMU_GLOBAL_CNTRL_FW_IS_PRESENT (1 << 4)
#define DRAM1_BASE 0x00000000ull
#define DRAM1_SIZE 0x10000000ull
#define DRAM1_END (DRAM1_BASE + DRAM1_SIZE - 1)
#define DRAM_BASE DRAM1_BASE
#define DRAM_SIZE DRAM1_SIZE
/* Load address of BL33 in the ZYNQMP port */
#define PLAT_ARM_NS_IMAGE_OFFSET (DRAM1_BASE + 0x8000000) /* DRAM + 128MB */
/*******************************************************************************
* CCI-400 related constants
******************************************************************************/
#define PLAT_ARM_CCI_BASE 0xFD6E0000
#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 3
#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 4
/*******************************************************************************
* GIC-400 & interrupt handling related constants
******************************************************************************/
#define BASE_GICD_BASE 0xF9010000
#define BASE_GICC_BASE 0xF9020000
#define BASE_GICH_BASE 0xF9040000
#define BASE_GICV_BASE 0xF9060000
#define IRQ_SEC_IPI_APU 67
#define ARM_IRQ_SEC_PHY_TIMER 29
#define ARM_IRQ_SEC_SGI_0 8
#define ARM_IRQ_SEC_SGI_1 9
#define ARM_IRQ_SEC_SGI_2 10
#define ARM_IRQ_SEC_SGI_3 11
#define ARM_IRQ_SEC_SGI_4 12
#define ARM_IRQ_SEC_SGI_5 13
#define ARM_IRQ_SEC_SGI_6 14
#define ARM_IRQ_SEC_SGI_7 15
#define MAX_INTR_EL3 128
/*******************************************************************************
* UART related constants
******************************************************************************/
#define ZYNQMP_UART0_BASE 0xFF000000
#define ZYNQMP_UART1_BASE 0xFF001000
#define PLAT_ARM_CRASH_UART_BASE ZYNQMP_UART0_BASE
/* impossible to call C routine how it is done now - hardcode any value */
#define PLAT_ARM_CRASH_UART_CLK_IN_HZ 100000000 /* FIXME */
/* Must be non zero */
#define ZYNQMP_UART_BAUDRATE 115200
#define ARM_CONSOLE_BAUDRATE ZYNQMP_UART_BAUDRATE
/* Silicon version detection */
#define ZYNQMP_SILICON_VER_MASK 0xF000
#define ZYNQMP_SILICON_VER_SHIFT 12
#define ZYNQMP_CSU_VERSION_SILICON 0
#define ZYNQMP_CSU_VERSION_EP108 1
#define ZYNQMP_CSU_VERSION_VELOCE 2
#define ZYNQMP_CSU_VERSION_QEMU 3
#define ZYNQMP_RTL_VER_MASK 0xFF0
#define ZYNQMP_RTL_VER_SHIFT 4
#define ZYNQMP_PS_VER_MASK 0xF
#define ZYNQMP_PS_VER_SHIFT 0
#define ZYNQMP_CSU_BASEADDR 0xFFCA0000
#define ZYNQMP_CSU_IDCODE_OFFSET 0x40
#define ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT 0
#define ZYNQMP_CSU_IDCODE_XILINX_ID_MASK (0xFFF << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT)
#define ZYNQMP_CSU_IDCODE_XILINX_ID 0x093
#define ZYNQMP_CSU_IDCODE_SVD_SHIFT 12
#define ZYNQMP_CSU_IDCODE_SVD_MASK (0xE << ZYNQMP_CSU_IDCODE_SVD_SHIFT)
#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT 15
#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK (0xF << ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT)
#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT 19
#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_MASK (0x3 << ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT)
#define ZYNQMP_CSU_IDCODE_FAMILY_SHIFT 21
#define ZYNQMP_CSU_IDCODE_FAMILY_MASK (0x7F << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT)
#define ZYNQMP_CSU_IDCODE_FAMILY 0x23
#define ZYNQMP_CSU_IDCODE_REVISION_SHIFT 28
#define ZYNQMP_CSU_IDCODE_REVISION_MASK (0xF << ZYNQMP_CSU_IDCODE_REVISION_SHIFT)
#define ZYNQMP_CSU_IDCODE_REVISION 0
#define ZYNQMP_CSU_VERSION_OFFSET 0x44
#endif /* __ZYNQMP_DEF_H__ */
/*
* Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __ZYNQMP_PRIVATE_H__
#define __ZYNQMP_PRIVATE_H__
#include <interrupt_mgmt.h>
void zynqmp_config_setup(void);
/* ZynqMP specific functions */
unsigned int zynqmp_get_uart_clk(void);
int zynqmp_is_pmu_up(void);
#endif /* __ZYNQMP_PRIVATE_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment