qcom: add initial SCM legacy API

This is a very simple implementation of Qualcomm's SCM API.

It is just the structure/field definitions and the atomic SCM
call which doesn't use the structs yet - it uses the field
definitions inside registers.

I've tested that setting the cold boot address via the atomic
API is fine - Linux does the same thing.  But not all SCM calls
can be done via the legacy API.

This is a reimplementation based on the Linux qualcomm SCM legacy
code and definitions.

Tested:

* Qualcomm IPQ4018 AP, as part of other changes for doing SMP bring-up

Reviewed by: andrew, manu, imp
Differential Revision: https://reviews.freebsd.org/D32723
This commit is contained in:
Adrian Chadd 2021-10-29 20:34:08 -07:00
parent a516ccc4ae
commit 960e65d23a
6 changed files with 404 additions and 0 deletions

View File

@ -25,6 +25,9 @@ device sdhci
device generic_timer
device mpcore_timer
# PSCI - SMC calls, needed for qualcomm SCM
device psci
options FDT
# Disable CP14 work in DDB as TZ won't let us by default

View File

@ -0,0 +1,122 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef __QCOM_SCM_DEFS_H__
#define __QCOM_SCM_DEFS_H__
/*
* Maximum SCM arguments and return values.
*/
#define MAX_QCOM_SCM_ARGS 10
#define MAX_QCOM_SCM_RETS 3
/*
* SCM argument type definitions.
*/
#define QCOM_SCM_ARGTYPE_VAL 0x00
#define QCOM_SCM_ARGTYPE_RO 0x01
#define QCOM_SCM_ARGTYPE_RW 0x02
#define QCOM_SCM_ARGTYPE_BUFVAL 0x03
/*
* SCM calls + arguments.
*/
#define QCOM_SCM_SVC_BOOT 0x01
#define QCOM_SCM_BOOT_SET_ADDR 0x01
#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
/* Flags for QCOM_SCM_BOOT_SET_ADDR argv[0] */
/* Note: no COLDBOOT for CPU0, it's already booted */
#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
#define QCOM_SCM_SVC_PIL 0x02
#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
#define QCOM_SCM_PIL_PAS_MEM_SETUP 0x02
#define QCOM_SCM_PIL_PAS_AUTH_AND_RESET 0x05
#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06
#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a
#define QCOM_SCM_SVC_IO 0x05
#define QCOM_SCM_IO_READ 0x01
#define QCOM_SCM_IO_WRITE 0x02
/*
* Fetch SCM call availability information.
*/
#define QCOM_SCM_SVC_INFO 0x06
#define QCOM_SCM_INFO_IS_CALL_AVAIL 0x01
#define QCOM_SCM_SVC_MP 0x0c
#define QCOM_SCM_MP_RESTORE_SEC_CFG 0x02
#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_SIZE 0x03
#define QCOM_SCM_MP_IOMMU_SECURE_PTBL_INIT 0x04
#define QCOM_SCM_MP_VIDEO_VAR 0x08
#define QCOM_SCM_MP_ASSIGN 0x16
#define QCOM_SCM_SVC_OCMEM 0x0f
#define QCOM_SCM_OCMEM_LOCK_CMD 0x01
#define QCOM_SCM_OCMEM_UNLOCK_CMD 0x02
#define QCOM_SCM_SVC_ES 0x10
#define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03
#define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04
#define QCOM_SCM_SVC_HDCP 0x11
#define QCOM_SCM_HDCP_INVOKE 0x01
#define QCOM_SCM_SVC_LMH 0x13
#define QCOM_SCM_LMH_LIMIT_PROFILE_CHANGE 0x01
#define QCOM_SCM_LMH_LIMIT_DCVSH 0x10
#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02
/*
* Return values from the SCM calls.
*/
#define QCOM_SCM_RETVAL_V2_EBUSY -12
#define QCOM_SCM_RETVAL_ENOMEM -5
#define QCOM_SCM_RETVAL_EOPNOTSUPP -4
#define QCOM_SCM_RETVAL_EINVAL_ADDR -3
#define QCOM_SCM_RETVAL_EINVAL_ARG -2
#define QCOM_SCM_RETVAL_ERROR -1
#define QCOM_SCM_RETVAL_INTERRUPTED 1
#endif /* __QCOM_SCM_DEFS_H__ */

View File

@ -0,0 +1,88 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 "opt_platform.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/reboot.h>
#include <sys/devmap.h>
#include <sys/smp.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/cpu.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/machdep.h>
#include <machine/smp.h>
#include <arm/qualcomm/qcom_scm_defs.h>
#include <arm/qualcomm/qcom_scm_legacy_defs.h>
#include <arm/qualcomm/qcom_scm_legacy.h>
#include <dev/psci/smccc.h>
/*
* Set the cold boot address for (later) a mask of CPUs.
*
* Don't set it for CPU0, that CPU is the boot CPU and is already alive.
*
* For now it sets it on CPU1..3.
*
* This works on the IPQ4019 as tested; the retval is 0x0.
*/
uint32_t
qcom_scm_legacy_mp_set_cold_boot_address(vm_offset_t mp_entry_func)
{
struct arm_smccc_res res;
int ret;
int context_id;
uint32_t scm_arg0 = QCOM_SCM_LEGACY_ATOMIC_ID(QCOM_SCM_SVC_BOOT,
QCOM_SCM_BOOT_SET_ADDR, 2);
uint32_t scm_arg1 = QCOM_SCM_FLAG_COLDBOOT_CPU1
| QCOM_SCM_FLAG_COLDBOOT_CPU2
| QCOM_SCM_FLAG_COLDBOOT_CPU3;
uint32_t scm_arg2 = pmap_kextract((vm_offset_t)mp_entry_func);
ret = arm_smccc_smc(scm_arg0, (uint32_t) &context_id, scm_arg1,
scm_arg2, 0, 0, 0, 0, &res);
if (ret == 0 && res.a0 == 0)
return (0);
printf("%s: called; error; ret=0x%08x; retval[0]=0x%08x\n",
__func__, ret, res.a0);
return (0);
}

View File

@ -0,0 +1,41 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef __QCOM_SCM_LEGACY_H__
#define __QCOM_SCM_LEGACY_H__
/*
* These functions are specific to the 32 bit legacy SCM interface
* used by the IPQ806x and IPQ401x SoCs.
*/
extern uint32_t qcom_scm_legacy_mp_set_cold_boot_address(
vm_offset_t mp_entry_func);
#endif /* __QCOM_SCM_LEGACY_H__ */

View File

@ -0,0 +1,149 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2021 Adrian Chadd <adrian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef __QCOM_SCM_LEGACY_DEFS_H__
#define __QCOM_SCM_LEGACY_DEFS_H__
/*
* These definitions are specific to the 32 bit legacy SCM interface
* used by the IPQ806x and IPQ401x SoCs.
*/
/*
* Mapping of the SCM service/command fields into the a0 argument
* in an SMC instruction call.
*
* This is particular to the legacy SCM interface, and is not the
* same as the non-legacy 32/64 bit FNID mapping layout.
*/
#define QCOM_SCM_LEGACY_SMC_FNID(s, c) (((s) << 10) | ((c) & 0x3ff))
/*
* There are two kinds of SCM calls in this legacy path.
*
* The first kind are the normal ones - up to a defined max of arguments,
* a defined max of responses and some identifiers for all of it.
* They can be issues in parallel on different cores, can be interrupted,
* etc.
*
* The second kind are what are termed "atomic" SCM calls -
* up to 5 argument DWORDs, up to 3 response DWORDs, done atomically,
* not interruptable/parallel.
*
* The former use the structures below to represent the request and response
* in memory. The latter use defines and a direct SMC call with the
* arguments in registers.
*/
struct qcom_scm_legacy_smc_args {
uint32_t args[8];
};
/*
* Atomic SCM call command/response buffer definitions.
*/
#define QCOM_SCM_LEGACY_ATOMIC_MAX_ARGCOUNT 5
#define QCOM_SCM_LEGACY_CLASS_REGISTER (0x2 << 8)
#define QCOM_SCM_LEGACY_MASK_IRQS (1U << 5)
/*
* Mapping an SCM service/command/argcount into the a0 register
* for an SMC instruction call.
*/
#define QCOM_SCM_LEGACY_ATOMIC_ID(svc, cmd, n) \
((QCOM_SCM_LEGACY_SMC_FNID((svc), cmd) << 12) | \
QCOM_SCM_LEGACY_CLASS_REGISTER | \
QCOM_SCM_LEGACY_MASK_IRQS | \
((n) & 0xf))
/*
* Legacy command/response buffer definitions.
*
* The legacy path contains up to the defined maximum arguments
* but only a single command/response pair per call.
*
* A command and response buffer is laid out in memory as such:
*
* | command header |
* | (buffer payload) |
* | response header |
* | (response payload) |
*/
/*
* The command header.
*
* len - the length of the total command and response, including
* the headers.
*
* buf_offset - the offset inside the buffer, starting at the
* beginning of this command header, where the command buffer
* is found. The end is the byte before the response_header_offset.
*
* response_header_offset - the offset inside the buffer where
* the response header is found.
*
* id - the QCOM_SCM_LEGACY_SMC_FNID() - service/command ids
*/
struct qcom_scm_legacy_command_header {
uint32_t len;
uint32_t buf_offset;
uint32_t response_header_offset;
uint32_t id;
};
/*
* The response header.
*
* This is found immediately after the command header and command
* buffer payload.
*
* len - the total amount of memory available for the response.
* Linux doesn't set this; it always passes in a response
* buffer large enough to store MAX_QCOM_SCM_RETS * DWORD
* bytes.
*
* It's also possible this is set by the firmware.
*
* buf_offset - start of response buffer, relative to the beginning
* of the command header. This also isn't set in Linux before
* calling the SMC instruction, but it is checked afterwards
* to assemble a pointer to the response data. The firmware
* likely sets this.
*
* is_complete - true if complete. Linux loops over DMA sync to
* check if this is complete even after the SMC call returns.
*/
struct qcom_scm_legacy_response_header {
uint32_t len;
uint32_t buf_offset;
uint32_t is_complete;
};
#endif /* __QCOM_SCM_LEGACY_DEFS_H__ */

View File

@ -1,4 +1,5 @@
arm/qualcomm/ipq4018_machdep.c standard
arm/qualcomm/ipq4018_mp.c optional smp
arm/qualcomm/qcom_scm_legacy.c standard
dev/qcom_rnd/qcom_rnd.c optional qcom_rnd