Qualcomm driver updates for v5.18

This refactors the Qualcomm mdt file loader, to partially decouple it
 from the SCM peripheral-authentication-service. This is needed as newer
 platforms, such as the Qualcomm SM8450, require the metadata to remain
 accessible to TrustZone during a longer time. This is followed by the
 introduction of remoteproc drivers for SM8450 (Snapdragon 8 Gen 1).
 
 It changes the way hardware version differences are handled in the LLCC
 driver and introduces support for Qualcomm SM8450. While updating the dt
 binding for LLCC it also introduces the missing SM8350 compatible.
 
 The ocmem and aoss drivers gains missing put_device() calls and rpmpd
 gains a missing check for kcalloc() failure.
 
 The SPM driver is updated to avoid instantiating the SPM cpuidle devices
 if the CPUs aren't controlled by SPM, such as when Snapdragon 8916
 operates in 32-bit mode without PSCI.
 
 The RPM power-domain driver gains MSM8226 support.
 
 Lastly the socinfo driver gains knowledge about a few new SoCs and
 PMICs.
 -----BEGIN PGP SIGNATURE-----
 
 iQJPBAABCAA5FiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAmIdnvAbHGJqb3JuLmFu
 ZGVyc3NvbkBsaW5hcm8ub3JnAAoJEAsfOT8Nma3FFMIQAL8yVzMuonz7yiuxZaC6
 nvCGWVIbsfjloLWjpE79orSoEx77DlhYaUDHdYqHMEV9ytdryaSaU5A5LGfzVugC
 D6TSvJh1SDV6hJ79xRZIDO72fJn/Xo62JCtTC4u+iBgoehhMrOQHm7HlBhLXJ2lq
 RiHDjzCHMaRTrPf1GCY8a1VK0nIa8KfaAbk+GzZ5Y+0I4oh7ea43DwUSYAIvZAKi
 N5CRXRFeoGpEnY9FzYYfkTPXu28hvj3NtGaEX8SIyzmgLBxCqLpFfxVj3xUsDGbX
 TFqr5YWO31/5oQN4Ex0IrD4NOyOtVyPCtd6iSmlW3t+LxcQsgfW4cCfzT9vQp8dV
 LLkhvKQCAMyIIzZtoHQRN2J0L4tQ8kW1lxW01XMbEjm0lOoALGisE8KouSPlAFn8
 zgX6bPWUmsuictfG8gmqgqKsloV6E5IU37Htcm+sdw89ZVks6UJG40D3DiOcpAXX
 eEKRMW8UHhR/u2AQRlaBcSTQVI/zfXWFk408zHxfD6fphrfnSPRBl+CEZmqrySWi
 eqsL1PJblZg1Uhg5Q8XRokAzB59RYVbs6jSiLKGTUvwTrBMUy+SK1UOG9V3pXsOv
 TSW92RXKZFS8smNcKm/2k1bhopW+2h2BB0z1OYBynl+VUOtCadf7DHciGmAn/Hxd
 eyL2HBVqS4LtdLHSL2TAj3oM
 =okza
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmIeZNUACgkQmmx57+YA
 GNmKBBAAwpweTveDkEmeT6nTckDaRYBo0LthJr6TmgndjKq5QChknEOFSMvs6JzP
 Ftheb+J7NcrQ20vN+wv8ic2k6hP8UCRrxyt7IJSJ3iDsqjODxW0K/qoetpFL1BoY
 zCdo0+C7R9iK4QbEA7HjbG5SCVMe8eOLGJLWXkbAO/DInU/WZfSmbbieDSNIjHIp
 nBoX5iBPKHMxj8Cbi12ezK+NHgwXkPdc+H0YNnwbBX6cr470bq5AarJCuWS4W0XP
 xUTC86mR9NUDMu4MkIjbtTZUgKOSXuQoioH4uJKNTDObD+i1GDUNWTm1nvxrQMe1
 DZctGN2ISHKjzcS2okcYwZ4CX8SEB3QK07YydyBknsNINxvwm1fB23VtCikP4k2r
 Zqo6ewT1Y1imrb2MmjWyTesXO1u+JDz5d0A3O9O93Yvfn6Zz/wiGQV6HSmbU6RpQ
 JyJWUOokCydqKXMLlb79Ln2Sx8q84aoZGekEQGfTqvIObntuYx0VWdMJuisP0z4+
 CqZTnIc60IaG8WkB/xx/vzzKa8XmKTfalSxZV5ThTruVmiHAqd1rW8N/mR4ZE2bM
 YQ0AxQcaZHyUawPuaqOY/u9lADE0ROW/3loC5CWU8LLTSR3OM610YgQOKNC8yi2n
 FlEYdhupJEGcx4fLY+SPWGgYFhIZgqxlL7WNtzg7uEFiBpayLxA=
 =vkG6
 -----END PGP SIGNATURE-----

Merge tag 'qcom-drivers-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/drivers

Qualcomm driver updates for v5.18

This refactors the Qualcomm mdt file loader, to partially decouple it
from the SCM peripheral-authentication-service. This is needed as newer
platforms, such as the Qualcomm SM8450, require the metadata to remain
accessible to TrustZone during a longer time. This is followed by the
introduction of remoteproc drivers for SM8450 (Snapdragon 8 Gen 1).

It changes the way hardware version differences are handled in the LLCC
driver and introduces support for Qualcomm SM8450. While updating the dt
binding for LLCC it also introduces the missing SM8350 compatible.

The ocmem and aoss drivers gains missing put_device() calls and rpmpd
gains a missing check for kcalloc() failure.

The SPM driver is updated to avoid instantiating the SPM cpuidle devices
if the CPUs aren't controlled by SPM, such as when Snapdragon 8916
operates in 32-bit mode without PSCI.

The RPM power-domain driver gains MSM8226 support.

Lastly the socinfo driver gains knowledge about a few new SoCs and
PMICs.

* tag 'qcom-drivers-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: (37 commits)
  soc: qcom: rpmpd: Add MSM8226 support
  dt-bindings: power: rpmpd: Add MSM8226 to rpmpd binding
  soc: qcom: mdt_loader: Fix split-firmware condition
  dt-bindings: arm: msm: Add LLCC compatible for SM8450
  dt-bindings: arm: msm: Add LLCC compatible for SM8350
  soc: qcom: llcc: Add configuration data for SM8450 SoC
  soc: qcom: llcc: Update register offsets for newer LLCC HW
  soc: qcom: llcc: Add missing llcc configuration data
  soc: qcom: llcc: Add write-cache cacheable support
  soc: qcom: llcc: Update the logic for version info extraction
  soc: qcom: llcc: Add support for 16 ways of allocation
  soc: qcom: socinfo: Add some more PMICs and SoCs
  firmware: qcom: scm: Add support for MC boot address API
  firmware: qcom: scm: Drop cpumask parameter from set_boot_addr()
  firmware: qcom: scm: Simplify set_cold/warm_boot_addr()
  cpuidle: qcom-spm: Check if any CPU is managed by SPM
  remoteproc: qcom: pas: Add SM8450 remoteproc support
  dt-bindings: remoteproc: qcom: pas: Add SM8450 PAS compatibles
  remoteproc: qcom: pas: Carry PAS metadata context
  soc: qcom: mdt_loader: Extract PAS operations
  ...

Link: https://lore.kernel.org/r/20220301042055.1804859-1-bjorn.andersson@linaro.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2022-03-01 19:24:20 +01:00
commit 4d558d4d88
20 changed files with 537 additions and 224 deletions

View file

@ -27,6 +27,8 @@ properties:
- qcom,sm6350-llcc
- qcom,sm8150-llcc
- qcom,sm8250-llcc
- qcom,sm8350-llcc
- qcom,sm8450-llcc
reg:
items:

View file

@ -17,6 +17,7 @@ properties:
compatible:
enum:
- qcom,mdm9607-rpmpd
- qcom,msm8226-rpmpd
- qcom,msm8916-rpmpd
- qcom,msm8939-rpmpd
- qcom,msm8953-rpmpd

View file

@ -47,6 +47,10 @@ properties:
- qcom,sm8350-cdsp-pas
- qcom,sm8350-slpi-pas
- qcom,sm8350-mpss-pas
- qcom,sm8450-adsp-pas
- qcom,sm8450-cdsp-pas
- qcom,sm8450-mpss-pas
- qcom,sm8450-slpi-pas
reg:
maxItems: 1
@ -175,6 +179,10 @@ allOf:
- qcom,sm8350-cdsp-pas
- qcom,sm8350-slpi-pas
- qcom,sm8350-mpss-pas
- qcom,sm8450-adsp-pas
- qcom,sm8450-cdsp-pas
- qcom,sm8450-slpi-pas
- qcom,sm8450-mpss-pas
then:
properties:
clocks:
@ -283,6 +291,9 @@ allOf:
- qcom,sm8350-adsp-pas
- qcom,sm8350-cdsp-pas
- qcom,sm8350-slpi-pas
- qcom,sm8450-adsp-pas
- qcom,sm8450-cdsp-pas
- qcom,sm8450-slpi-pas
then:
properties:
interrupts:
@ -312,6 +323,7 @@ allOf:
- qcom,sm6350-mpss-pas
- qcom,sm8150-mpss-pas
- qcom,sm8350-mpss-pas
- qcom,sm8450-mpss-pas
then:
properties:
interrupts:
@ -434,6 +446,7 @@ allOf:
- qcom,sm6350-mpss-pas
- qcom,sm8150-mpss-pas
- qcom,sm8350-mpss-pas
- qcom,sm8450-mpss-pas
then:
properties:
power-domains:
@ -458,6 +471,8 @@ allOf:
- qcom,sm8250-slpi-pas
- qcom,sm8350-adsp-pas
- qcom,sm8350-slpi-pas
- qcom,sm8450-adsp-pas
- qcom,sm8450-slpi-pas
then:
properties:
power-domains:
@ -475,6 +490,7 @@ allOf:
contains:
enum:
- qcom,sm8350-cdsp-pas
- qcom,sm8450-cdsp-pas
then:
properties:
power-domains:

View file

@ -357,8 +357,7 @@ static void __init qcom_smp_prepare_cpus(unsigned int max_cpus)
{
int cpu;
if (qcom_scm_set_cold_boot_addr(secondary_startup_arm,
cpu_present_mask)) {
if (qcom_scm_set_cold_boot_addr(secondary_startup_arm)) {
for_each_present_cpu(cpu) {
if (cpu == smp_processor_id())
continue;

View file

@ -122,10 +122,6 @@ static int spm_cpuidle_register(struct device *cpuidle_dev, int cpu)
if (ret <= 0)
return ret ? : -ENODEV;
ret = qcom_scm_set_warm_boot_addr(cpu_resume_arm, cpumask_of(cpu));
if (ret)
return ret;
return cpuidle_register(&data->cpuidle_driver, NULL);
}
@ -136,6 +132,10 @@ static int spm_cpuidle_drv_probe(struct platform_device *pdev)
if (!qcom_scm_is_available())
return -EPROBE_DEFER;
ret = qcom_scm_set_warm_boot_addr(cpu_resume_arm);
if (ret)
return dev_err_probe(&pdev->dev, ret, "set warm boot addr failed");
for_each_possible_cpu(cpu) {
ret = spm_cpuidle_register(&pdev->dev, cpu);
if (ret && ret != -ENODEV) {
@ -155,6 +155,22 @@ static struct platform_driver spm_cpuidle_driver = {
},
};
static bool __init qcom_spm_find_any_cpu(void)
{
struct device_node *cpu_node, *saw_node;
for_each_of_cpu_node(cpu_node) {
saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
if (of_device_is_available(saw_node)) {
of_node_put(saw_node);
of_node_put(cpu_node);
return true;
}
of_node_put(saw_node);
}
return false;
}
static int __init qcom_spm_cpuidle_init(void)
{
struct platform_device *pdev;
@ -164,6 +180,10 @@ static int __init qcom_spm_cpuidle_init(void)
if (ret)
return ret;
/* Make sure there is actually any CPU managed by the SPM */
if (!qcom_spm_find_any_cpu())
return 0;
pdev = platform_device_register_simple("qcom-spm-cpuidle",
-1, NULL, 0);
if (IS_ERR(pdev)) {

View file

@ -49,26 +49,12 @@ struct qcom_scm_mem_map_info {
__le64 mem_size;
};
#define QCOM_SCM_FLAG_COLDBOOT_CPU0 0x00
#define QCOM_SCM_FLAG_COLDBOOT_CPU1 0x01
#define QCOM_SCM_FLAG_COLDBOOT_CPU2 0x08
#define QCOM_SCM_FLAG_COLDBOOT_CPU3 0x20
#define QCOM_SCM_FLAG_WARMBOOT_CPU0 0x04
#define QCOM_SCM_FLAG_WARMBOOT_CPU1 0x02
#define QCOM_SCM_FLAG_WARMBOOT_CPU2 0x10
#define QCOM_SCM_FLAG_WARMBOOT_CPU3 0x40
struct qcom_scm_wb_entry {
int flag;
void *entry;
/* Each bit configures cold/warm boot address for one of the 4 CPUs */
static const u8 qcom_scm_cpu_cold_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
0, BIT(0), BIT(3), BIT(5)
};
static struct qcom_scm_wb_entry qcom_scm_wb[] = {
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU0 },
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU1 },
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU2 },
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
BIT(2), BIT(1), BIT(4), BIT(6)
};
static const char * const qcom_scm_convention_names[] = {
@ -179,9 +165,8 @@ static enum qcom_scm_convention __get_convention(void)
/**
* qcom_scm_call() - Invoke a syscall in the secure world
* @dev: device
* @svc_id: service identifier
* @cmd_id: command identifier
* @desc: Descriptor structure containing arguments and return values
* @res: Structure containing results from SMC/HVC call
*
* Sends a command to the SCM and waits for the command to finish processing.
* This should *only* be called in pre-emptible context.
@ -205,8 +190,6 @@ static int qcom_scm_call(struct device *dev, const struct qcom_scm_desc *desc,
/**
* qcom_scm_call_atomic() - atomic variation of qcom_scm_call()
* @dev: device
* @svc_id: service identifier
* @cmd_id: command identifier
* @desc: Descriptor structure containing arguments and return values
* @res: Structure containing results from SMC/HVC call
*
@ -260,70 +243,10 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
return ret ? false : !!res.result[0];
}
/**
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus
* @entry: Entry point function for the cpus
* @cpus: The cpumask of cpus that will use the entry point
*
* Set the Linux entry point for the SCM to transfer control to when coming
* out of a power down. CPU power down may be executed on cpuidle or hotplug.
*/
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
static int qcom_scm_set_boot_addr(void *entry, const u8 *cpu_bits)
{
int ret;
int flags = 0;
int cpu;
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_BOOT,
.cmd = QCOM_SCM_BOOT_SET_ADDR,
.arginfo = QCOM_SCM_ARGS(2),
};
/*
* Reassign only if we are switching from hotplug entry point
* to cpuidle entry point or vice versa.
*/
for_each_cpu(cpu, cpus) {
if (entry == qcom_scm_wb[cpu].entry)
continue;
flags |= qcom_scm_wb[cpu].flag;
}
/* No change in entry function */
if (!flags)
return 0;
desc.args[0] = flags;
desc.args[1] = virt_to_phys(entry);
ret = qcom_scm_call(__scm->dev, &desc, NULL);
if (!ret) {
for_each_cpu(cpu, cpus)
qcom_scm_wb[cpu].entry = entry;
}
return ret;
}
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
/**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
* @entry: Entry point function for the cpus
* @cpus: The cpumask of cpus that will use the entry point
*
* Set the cold boot address of the cpus. Any cpu outside the supported
* range would be removed from the cpu present mask.
*/
int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
{
int flags = 0;
int cpu;
int scm_cb_flags[] = {
QCOM_SCM_FLAG_COLDBOOT_CPU0,
QCOM_SCM_FLAG_COLDBOOT_CPU1,
QCOM_SCM_FLAG_COLDBOOT_CPU2,
QCOM_SCM_FLAG_COLDBOOT_CPU3,
};
unsigned int flags = 0;
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_BOOT,
.cmd = QCOM_SCM_BOOT_SET_ADDR,
@ -331,14 +254,10 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
.owner = ARM_SMCCC_OWNER_SIP,
};
if (!cpus || cpumask_empty(cpus))
return -EINVAL;
for_each_cpu(cpu, cpus) {
if (cpu < ARRAY_SIZE(scm_cb_flags))
flags |= scm_cb_flags[cpu];
else
set_cpu_present(cpu, false);
for_each_present_cpu(cpu) {
if (cpu >= QCOM_SCM_BOOT_MAX_CPUS)
return -EINVAL;
flags |= cpu_bits[cpu];
}
desc.args[0] = flags;
@ -346,11 +265,61 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
return qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL);
}
static int qcom_scm_set_boot_addr_mc(void *entry, unsigned int flags)
{
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_BOOT,
.cmd = QCOM_SCM_BOOT_SET_ADDR_MC,
.owner = ARM_SMCCC_OWNER_SIP,
.arginfo = QCOM_SCM_ARGS(6),
.args = {
virt_to_phys(entry),
/* Apply to all CPUs in all affinity levels */
~0ULL, ~0ULL, ~0ULL, ~0ULL,
flags,
},
};
/* Need a device for DMA of the additional arguments */
if (!__scm || __get_convention() == SMC_CONVENTION_LEGACY)
return -EOPNOTSUPP;
return qcom_scm_call(__scm->dev, &desc, NULL);
}
/**
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for all cpus
* @entry: Entry point function for the cpus
*
* Set the Linux entry point for the SCM to transfer control to when coming
* out of a power down. CPU power down may be executed on cpuidle or hotplug.
*/
int qcom_scm_set_warm_boot_addr(void *entry)
{
if (qcom_scm_set_boot_addr_mc(entry, QCOM_SCM_BOOT_MC_FLAG_WARMBOOT))
/* Fallback to old SCM call */
return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_warm_bits);
return 0;
}
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
/**
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for all cpus
* @entry: Entry point function for the cpus
*/
int qcom_scm_set_cold_boot_addr(void *entry)
{
if (qcom_scm_set_boot_addr_mc(entry, QCOM_SCM_BOOT_MC_FLAG_COLDBOOT))
/* Fallback to old SCM call */
return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_cold_bits);
return 0;
}
EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
/**
* qcom_scm_cpu_power_down() - Power down the cpu
* @flags - Flags to flush cache
* @flags: Flags to flush cache
*
* This is an end point to power down cpu. If there was a pending interrupt,
* the control would return from this function, otherwise, the cpu jumps to the
@ -435,10 +404,16 @@ static void qcom_scm_set_download_mode(bool enable)
* and optional blob of data used for authenticating the metadata
* and the rest of the firmware
* @size: size of the metadata
* @ctx: optional metadata context
*
* Returns 0 on success.
* Return: 0 on success.
*
* Upon successful return, the PAS metadata context (@ctx) will be used to
* track the metadata allocation, this needs to be released by invoking
* qcom_scm_pas_metadata_release() by the caller.
*/
int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
struct qcom_scm_pas_metadata *ctx)
{
dma_addr_t mdata_phys;
void *mdata_buf;
@ -467,7 +442,7 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
ret = qcom_scm_clk_enable();
if (ret)
goto free_metadata;
goto out;
desc.args[1] = mdata_phys;
@ -475,13 +450,36 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size)
qcom_scm_clk_disable();
free_metadata:
dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
out:
if (ret < 0 || !ctx) {
dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
} else if (ctx) {
ctx->ptr = mdata_buf;
ctx->phys = mdata_phys;
ctx->size = size;
}
return ret ? : res.result[0];
}
EXPORT_SYMBOL(qcom_scm_pas_init_image);
/**
* qcom_scm_pas_metadata_release() - release metadata context
* @ctx: metadata context
*/
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx)
{
if (!ctx->ptr)
return;
dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
ctx->ptr = NULL;
ctx->phys = 0;
ctx->size = 0;
}
EXPORT_SYMBOL(qcom_scm_pas_metadata_release);
/**
* qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
* for firmware loading
@ -749,12 +747,6 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
};
int ret;
desc.args[0] = addr;
desc.args[1] = size;
desc.args[2] = spare;
desc.arginfo = QCOM_SCM_ARGS(3, QCOM_SCM_RW, QCOM_SCM_VAL,
QCOM_SCM_VAL);
ret = qcom_scm_call(__scm->dev, &desc, NULL);
/* the pg table has been initialized already, ignore the error */
@ -765,6 +757,21 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare)
}
EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init);
int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size)
{
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_MP,
.cmd = QCOM_SCM_MP_IOMMU_SET_CP_POOL_SIZE,
.arginfo = QCOM_SCM_ARGS(2),
.args[0] = size,
.args[1] = spare,
.owner = ARM_SMCCC_OWNER_SIP,
};
return qcom_scm_call(__scm->dev, &desc, NULL);
}
EXPORT_SYMBOL(qcom_scm_iommu_set_cp_pool_size);
int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size,
u32 cp_nonpixel_start,
u32 cp_nonpixel_size)
@ -1131,6 +1138,22 @@ int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
}
EXPORT_SYMBOL(qcom_scm_hdcp_req);
int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt)
{
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_SMMU_PROGRAM,
.cmd = QCOM_SCM_SMMU_PT_FORMAT,
.arginfo = QCOM_SCM_ARGS(3),
.args[0] = sec_id,
.args[1] = ctx_num,
.args[2] = pt_fmt, /* 0: LPAE AArch32 - 1: AArch64 */
.owner = ARM_SMCCC_OWNER_SIP,
};
return qcom_scm_call(__scm->dev, &desc, NULL);
}
EXPORT_SYMBOL(qcom_scm_iommu_set_pt_format);
int qcom_scm_qsmmu500_wait_safe_toggle(bool en)
{
struct qcom_scm_desc desc = {

View file

@ -78,8 +78,13 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
#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_ADDR_MC 0x11
#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
#define QCOM_SCM_FLUSH_FLAG_MASK 0x3
#define QCOM_SCM_BOOT_MAX_CPUS 4
#define QCOM_SCM_BOOT_MC_FLAG_AARCH64 BIT(0)
#define QCOM_SCM_BOOT_MC_FLAG_COLDBOOT BIT(1)
#define QCOM_SCM_BOOT_MC_FLAG_WARMBOOT BIT(2)
#define QCOM_SCM_SVC_PIL 0x02
#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
@ -100,6 +105,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
#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_IOMMU_SET_CP_POOL_SIZE 0x05
#define QCOM_SCM_MP_VIDEO_VAR 0x08
#define QCOM_SCM_MP_ASSIGN 0x16
@ -119,6 +125,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
#define QCOM_SCM_LMH_LIMIT_DCVSH 0x10
#define QCOM_SCM_SVC_SMMU_PROGRAM 0x15
#define QCOM_SCM_SMMU_PT_FORMAT 0x01
#define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03
#define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02

View file

@ -928,7 +928,8 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc,
regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0);
}
static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw,
const char *fw_name)
{
unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS;
dma_addr_t phys;
@ -939,7 +940,7 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw)
void *ptr;
int ret;
metadata = qcom_mdt_read_metadata(fw, &size);
metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev);
if (IS_ERR(metadata))
return PTR_ERR(metadata);
@ -1289,7 +1290,7 @@ static int q6v5_mpss_load(struct q6v5 *qproc)
/* Initialize the RMB validator */
writel(0, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG);
ret = q6v5_mpss_init_image(qproc, fw);
ret = q6v5_mpss_init_image(qproc, fw, qproc->hexagon_mdt_image);
if (ret)
goto release_firmware;

View file

@ -79,6 +79,8 @@ struct qcom_adsp {
struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_ssr ssr_subdev;
struct qcom_sysmon *sysmon;
struct qcom_scm_pas_metadata pas_metadata;
};
static void adsp_minidump(struct rproc *rproc)
@ -126,14 +128,34 @@ static void adsp_pds_disable(struct qcom_adsp *adsp, struct device **pds,
}
}
static int adsp_unprepare(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
/*
* adsp_load() did pass pas_metadata to the SCM driver for storing
* metadata context. It might have been released already if
* auth_and_reset() was successful, but in other cases clean it up
* here.
*/
qcom_scm_pas_metadata_release(&adsp->pas_metadata);
return 0;
}
static int adsp_load(struct rproc *rproc, const struct firmware *fw)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
int ret;
ret = qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id,
adsp->mem_region, adsp->mem_phys, adsp->mem_size,
&adsp->mem_reloc);
ret = qcom_mdt_pas_init(adsp->dev, fw, rproc->firmware, adsp->pas_id,
adsp->mem_phys, &adsp->pas_metadata);
if (ret)
return ret;
ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, adsp->pas_id,
adsp->mem_region, adsp->mem_phys, adsp->mem_size,
&adsp->mem_reloc);
if (ret)
return ret;
@ -185,6 +207,8 @@ static int adsp_start(struct rproc *rproc)
goto disable_px_supply;
}
qcom_scm_pas_metadata_release(&adsp->pas_metadata);
return 0;
disable_px_supply:
@ -255,6 +279,7 @@ static unsigned long adsp_panic(struct rproc *rproc)
}
static const struct rproc_ops adsp_ops = {
.unprepare = adsp_unprepare,
.start = adsp_start,
.stop = adsp_stop,
.da_to_va = adsp_da_to_va,
@ -264,6 +289,7 @@ static const struct rproc_ops adsp_ops = {
};
static const struct rproc_ops adsp_minidump_ops = {
.unprepare = adsp_unprepare,
.start = adsp_start,
.stop = adsp_stop,
.da_to_va = adsp_da_to_va,
@ -853,6 +879,10 @@ static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,sm8350-cdsp-pas", .data = &sm8350_cdsp_resource},
{ .compatible = "qcom,sm8350-slpi-pas", .data = &sm8350_slpi_resource},
{ .compatible = "qcom,sm8350-mpss-pas", .data = &mpss_resource_init},
{ .compatible = "qcom,sm8450-adsp-pas", .data = &sm8350_adsp_resource},
{ .compatible = "qcom,sm8450-cdsp-pas", .data = &sm8350_cdsp_resource},
{ .compatible = "qcom,sm8450-slpi-pas", .data = &sm8350_slpi_resource},
{ .compatible = "qcom,sm8450-mpss-pas", .data = &mpss_resource_init},
{ },
};
MODULE_DEVICE_TABLE(of, adsp_of_match);

View file

@ -653,7 +653,6 @@ static void apr_remove(struct rpmsg_device *rpdev)
pdr_handle_release(apr->pdr);
device_for_each_child(&rpdev->dev, NULL, apr_remove_device);
flush_workqueue(apr->rxwq);
destroy_workqueue(apr->rxwq);
}

View file

@ -29,17 +29,13 @@
#define ATTR1_FIXED_SIZE_SHIFT 0x03
#define ATTR1_PRIORITY_SHIFT 0x04
#define ATTR1_MAX_CAP_SHIFT 0x10
#define ATTR0_RES_WAYS_MASK GENMASK(11, 0)
#define ATTR0_BONUS_WAYS_MASK GENMASK(27, 16)
#define ATTR0_RES_WAYS_MASK GENMASK(15, 0)
#define ATTR0_BONUS_WAYS_MASK GENMASK(31, 16)
#define ATTR0_BONUS_WAYS_SHIFT 0x10
#define LLCC_STATUS_READ_DELAY 100
#define CACHE_LINE_SIZE_SHIFT 6
#define LLCC_COMMON_HW_INFO 0x00030000
#define LLCC_MAJOR_VERSION_MASK GENMASK(31, 24)
#define LLCC_COMMON_STATUS0 0x0003000c
#define LLCC_LB_CNT_MASK GENMASK(31, 28)
#define LLCC_LB_CNT_SHIFT 28
@ -52,9 +48,13 @@
#define LLCC_TRP_SCID_DIS_CAP_ALLOC 0x21f00
#define LLCC_TRP_PCB_ACT 0x21f04
#define LLCC_TRP_WRSC_EN 0x21f20
#define LLCC_TRP_WRSC_CACHEABLE_EN 0x21f2c
#define BANK_OFFSET_STRIDE 0x80000
#define LLCC_VERSION_2_0_0_0 0x02000000
#define LLCC_VERSION_2_1_0_0 0x02010000
/**
* struct llcc_slice_config - Data associated with the llcc slice
* @usecase_id: Unique id for the client's use case
@ -79,6 +79,8 @@
* collapse.
* @activate_on_init: Activate the slice immediately after it is programmed
* @write_scid_en: Bit enables write cache support for a given scid.
* @write_scid_cacheable_en: Enables write cache cacheable support for a
* given scid (not supported on v2 or older hardware).
*/
struct llcc_slice_config {
u32 usecase_id;
@ -94,12 +96,19 @@ struct llcc_slice_config {
bool retain_on_pc;
bool activate_on_init;
bool write_scid_en;
bool write_scid_cacheable_en;
};
struct qcom_llcc_config {
const struct llcc_slice_config *sct_data;
int size;
bool need_llcc_cfg;
const u32 *reg_offset;
};
enum llcc_reg_offset {
LLCC_COMMON_HW_INFO,
LLCC_COMMON_STATUS0,
};
static const struct llcc_slice_config sc7180_data[] = {
@ -217,42 +226,96 @@ static const struct llcc_slice_config sm8350_data[] = {
{ LLCC_CPUHWT, 5, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 },
};
static const struct llcc_slice_config sm8450_data[] = {
{LLCC_CPUSS, 1, 3072, 1, 0, 0xFFFF, 0x0, 0, 0, 0, 1, 1, 0, 0 },
{LLCC_VIDSC0, 2, 512, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_AUDIO, 6, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
{LLCC_MDMHPGRW, 7, 1024, 3, 0, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_MODHW, 9, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_CMPT, 10, 4096, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_GPUHTW, 11, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_GPU, 12, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 1, 0 },
{LLCC_MMUHWT, 13, 768, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0 },
{LLCC_DISP, 16, 4096, 2, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_MDMPNG, 21, 1024, 1, 1, 0xF000, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_AUDHW, 22, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
{LLCC_CVP, 28, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_MODPE, 29, 64, 1, 1, 0xF000, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xF0, 1, 0, 0, 1, 0, 0, 0 },
{LLCC_WRCACHE, 31, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 1, 0, 0 },
{LLCC_CVPFW, 17, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_CPUSS1, 3, 1024, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_CAMEXP0, 4, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_CPUMTE, 23, 256, 1, 1, 0x0FFF, 0x0, 0, 0, 0, 0, 1, 0, 0 },
{LLCC_CPUHWT, 5, 512, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 1, 0, 0 },
{LLCC_CAMEXP1, 27, 256, 3, 1, 0xFFFF, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{LLCC_AENPU, 8, 2048, 1, 1, 0xFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0 },
};
static const u32 llcc_v1_2_reg_offset[] = {
[LLCC_COMMON_HW_INFO] = 0x00030000,
[LLCC_COMMON_STATUS0] = 0x0003000c,
};
static const u32 llcc_v21_reg_offset[] = {
[LLCC_COMMON_HW_INFO] = 0x00034000,
[LLCC_COMMON_STATUS0] = 0x0003400c,
};
static const struct qcom_llcc_config sc7180_cfg = {
.sct_data = sc7180_data,
.size = ARRAY_SIZE(sc7180_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
};
static const struct qcom_llcc_config sc7280_cfg = {
.sct_data = sc7280_data,
.size = ARRAY_SIZE(sc7280_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
};
static const struct qcom_llcc_config sdm845_cfg = {
.sct_data = sdm845_data,
.size = ARRAY_SIZE(sdm845_data),
.need_llcc_cfg = false,
.reg_offset = llcc_v1_2_reg_offset,
};
static const struct qcom_llcc_config sm6350_cfg = {
.sct_data = sm6350_data,
.size = ARRAY_SIZE(sm6350_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
};
static const struct qcom_llcc_config sm8150_cfg = {
.sct_data = sm8150_data,
.size = ARRAY_SIZE(sm8150_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
};
static const struct qcom_llcc_config sm8250_cfg = {
.sct_data = sm8250_data,
.size = ARRAY_SIZE(sm8250_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
};
static const struct qcom_llcc_config sm8350_cfg = {
.sct_data = sm8350_data,
.size = ARRAY_SIZE(sm8350_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_2_reg_offset,
};
static const struct qcom_llcc_config sm8450_cfg = {
.sct_data = sm8450_data,
.size = ARRAY_SIZE(sm8450_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v21_reg_offset,
};
static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
@ -504,7 +567,7 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
return ret;
}
if (drv_data->major_version == 2) {
if (drv_data->version >= LLCC_VERSION_2_0_0_0) {
u32 wren;
wren = config->write_scid_en << config->slice_id;
@ -514,6 +577,16 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
return ret;
}
if (drv_data->version >= LLCC_VERSION_2_1_0_0) {
u32 wr_cache_en;
wr_cache_en = config->write_scid_cacheable_en << config->slice_id;
ret = regmap_update_bits(drv_data->bcast_regmap, LLCC_TRP_WRSC_CACHEABLE_EN,
BIT(config->slice_id), wr_cache_en);
if (ret)
return ret;
}
if (config->activate_on_init) {
desc.slice_id = config->slice_id;
ret = llcc_slice_activate(&desc);
@ -598,15 +671,18 @@ static int qcom_llcc_probe(struct platform_device *pdev)
goto err;
}
/* Extract major version of the IP */
ret = regmap_read(drv_data->bcast_regmap, LLCC_COMMON_HW_INFO, &version);
cfg = of_device_get_match_data(&pdev->dev);
/* Extract version of the IP */
ret = regmap_read(drv_data->bcast_regmap, cfg->reg_offset[LLCC_COMMON_HW_INFO],
&version);
if (ret)
goto err;
drv_data->major_version = FIELD_GET(LLCC_MAJOR_VERSION_MASK, version);
drv_data->version = version;
ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
&num_banks);
ret = regmap_read(drv_data->regmap, cfg->reg_offset[LLCC_COMMON_STATUS0],
&num_banks);
if (ret)
goto err;
@ -614,7 +690,6 @@ static int qcom_llcc_probe(struct platform_device *pdev)
num_banks >>= LLCC_LB_CNT_SHIFT;
drv_data->num_banks = num_banks;
cfg = of_device_get_match_data(&pdev->dev);
llcc_cfg = cfg->sct_data;
sz = cfg->size;
@ -632,9 +707,8 @@ static int qcom_llcc_probe(struct platform_device *pdev)
for (i = 0; i < num_banks; i++)
drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
drv_data->bitmap = devm_kcalloc(dev,
BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
GFP_KERNEL);
drv_data->bitmap = devm_bitmap_zalloc(dev, drv_data->max_slices,
GFP_KERNEL);
if (!drv_data->bitmap) {
ret = -ENOMEM;
goto err;
@ -672,6 +746,7 @@ static const struct of_device_id qcom_llcc_of_match[] = {
{ .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg },
{ .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg },
{ .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg },
{ .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfg },
{ }
};

View file

@ -31,6 +31,44 @@ static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
return true;
}
static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs,
unsigned int segment, const char *fw_name,
struct device *dev)
{
const struct elf32_phdr *phdr = &phdrs[segment];
const struct firmware *seg_fw;
char *seg_name;
ssize_t ret;
if (strlen(fw_name) < 4)
return -EINVAL;
seg_name = kstrdup(fw_name, GFP_KERNEL);
if (!seg_name)
return -ENOMEM;
sprintf(seg_name + strlen(fw_name) - 3, "b%02d", segment);
ret = request_firmware_into_buf(&seg_fw, seg_name, dev,
ptr, phdr->p_filesz);
if (ret) {
dev_err(dev, "error %zd loading %s\n", ret, seg_name);
kfree(seg_name);
return ret;
}
if (seg_fw->size != phdr->p_filesz) {
dev_err(dev,
"failed to load segment %d from truncated file %s\n",
segment, seg_name);
ret = -EINVAL;
}
release_firmware(seg_fw);
kfree(seg_name);
return ret;
}
/**
* qcom_mdt_get_size() - acquire size of the memory region needed to load mdt
* @fw: firmware object for the mdt file
@ -83,13 +121,17 @@ EXPORT_SYMBOL_GPL(qcom_mdt_get_size);
*
* Return: pointer to data, or ERR_PTR()
*/
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
const char *fw_name, struct device *dev)
{
const struct elf32_phdr *phdrs;
const struct elf32_hdr *ehdr;
unsigned int hash_segment = 0;
size_t hash_offset;
size_t hash_size;
size_t ehdr_size;
unsigned int i;
ssize_t ret;
void *data;
ehdr = (struct elf32_hdr *)fw->data;
@ -101,24 +143,44 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
if (phdrs[0].p_type == PT_LOAD)
return ERR_PTR(-EINVAL);
if ((phdrs[1].p_flags & QCOM_MDT_TYPE_MASK) != QCOM_MDT_TYPE_HASH)
for (i = 1; i < ehdr->e_phnum; i++) {
if ((phdrs[i].p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) {
hash_segment = i;
break;
}
}
if (!hash_segment) {
dev_err(dev, "no hash segment found in %s\n", fw_name);
return ERR_PTR(-EINVAL);
}
ehdr_size = phdrs[0].p_filesz;
hash_size = phdrs[1].p_filesz;
hash_size = phdrs[hash_segment].p_filesz;
data = kmalloc(ehdr_size + hash_size, GFP_KERNEL);
if (!data)
return ERR_PTR(-ENOMEM);
/* Is the header and hash already packed */
if (ehdr_size + hash_size == fw->size)
hash_offset = phdrs[0].p_filesz;
else
hash_offset = phdrs[1].p_offset;
/* Copy ELF header */
memcpy(data, fw->data, ehdr_size);
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
if (ehdr_size + hash_size == fw->size) {
/* Firmware is split and hash is packed following the ELF header */
hash_offset = phdrs[0].p_filesz;
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
} else if (phdrs[hash_segment].p_offset + hash_size <= fw->size) {
/* Hash is in its own segment, but within the loaded file */
hash_offset = phdrs[hash_segment].p_offset;
memcpy(data + ehdr_size, fw->data + hash_offset, hash_size);
} else {
/* Hash is in its own segment, beyond the loaded file */
ret = mdt_load_split_segment(data + ehdr_size, phdrs, hash_segment, fw_name, dev);
if (ret) {
kfree(data);
return ERR_PTR(ret);
}
}
*data_len = ehdr_size + hash_size;
@ -126,23 +188,85 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len)
}
EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata);
/**
* qcom_mdt_pas_init() - initialize PAS region for firmware loading
* @dev: device handle to associate resources with
* @fw: firmware object for the mdt file
* @firmware: name of the firmware, for construction of segment file names
* @pas_id: PAS identifier
* @mem_phys: physical address of allocated memory region
* @ctx: PAS metadata context, to be released by caller
*
* Returns 0 on success, negative errno otherwise.
*/
int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, phys_addr_t mem_phys,
struct qcom_scm_pas_metadata *ctx)
{
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
const struct elf32_hdr *ehdr;
phys_addr_t min_addr = PHYS_ADDR_MAX;
phys_addr_t max_addr = 0;
size_t metadata_len;
void *metadata;
int ret;
int i;
ehdr = (struct elf32_hdr *)fw->data;
phdrs = (struct elf32_phdr *)(ehdr + 1);
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
if (!mdt_phdr_valid(phdr))
continue;
if (phdr->p_paddr < min_addr)
min_addr = phdr->p_paddr;
if (phdr->p_paddr + phdr->p_memsz > max_addr)
max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
}
metadata = qcom_mdt_read_metadata(fw, &metadata_len, fw_name, dev);
if (IS_ERR(metadata)) {
ret = PTR_ERR(metadata);
dev_err(dev, "error %d reading firmware %s metadata\n", ret, fw_name);
goto out;
}
ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len, ctx);
kfree(metadata);
if (ret) {
/* Invalid firmware metadata */
dev_err(dev, "error %d initializing firmware %s\n", ret, fw_name);
goto out;
}
ret = qcom_scm_pas_mem_setup(pas_id, mem_phys, max_addr - min_addr);
if (ret) {
/* Unable to set up relocation */
dev_err(dev, "error %d setting up firmware %s\n", ret, fw_name);
goto out;
}
out:
return ret;
}
EXPORT_SYMBOL_GPL(qcom_mdt_pas_init);
static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
const char *firmware, int pas_id, void *mem_region,
const char *fw_name, int pas_id, void *mem_region,
phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base, bool pas_init)
{
const struct elf32_phdr *phdrs;
const struct elf32_phdr *phdr;
const struct elf32_hdr *ehdr;
const struct firmware *seg_fw;
phys_addr_t mem_reloc;
phys_addr_t min_addr = PHYS_ADDR_MAX;
phys_addr_t max_addr = 0;
size_t metadata_len;
size_t fw_name_len;
ssize_t offset;
void *metadata;
char *fw_name;
bool relocate = false;
void *ptr;
int ret = 0;
@ -154,34 +278,6 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
ehdr = (struct elf32_hdr *)fw->data;
phdrs = (struct elf32_phdr *)(ehdr + 1);
fw_name_len = strlen(firmware);
if (fw_name_len <= 4)
return -EINVAL;
fw_name = kstrdup(firmware, GFP_KERNEL);
if (!fw_name)
return -ENOMEM;
if (pas_init) {
metadata = qcom_mdt_read_metadata(fw, &metadata_len);
if (IS_ERR(metadata)) {
ret = PTR_ERR(metadata);
dev_err(dev, "error %d reading firmware %s metadata\n",
ret, fw_name);
goto out;
}
ret = qcom_scm_pas_init_image(pas_id, metadata, metadata_len);
kfree(metadata);
if (ret) {
/* Invalid firmware metadata */
dev_err(dev, "error %d initializing firmware %s\n",
ret, fw_name);
goto out;
}
}
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
@ -193,23 +289,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
if (phdr->p_paddr < min_addr)
min_addr = phdr->p_paddr;
if (phdr->p_paddr + phdr->p_memsz > max_addr)
max_addr = ALIGN(phdr->p_paddr + phdr->p_memsz, SZ_4K);
}
if (relocate) {
if (pas_init) {
ret = qcom_scm_pas_mem_setup(pas_id, mem_phys,
max_addr - min_addr);
if (ret) {
/* Unable to set up relocation */
dev_err(dev, "error %d setting up firmware %s\n",
ret, fw_name);
goto out;
}
}
/*
* The image is relocatable, so offset each segment based on
* the lowest segment address.
@ -246,7 +328,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
ptr = mem_region + offset;
if (phdr->p_filesz && phdr->p_offset < fw->size) {
if (phdr->p_filesz && phdr->p_offset < fw->size &&
phdr->p_offset + phdr->p_filesz <= fw->size) {
/* Firmware is large enough to be non-split */
if (phdr->p_offset + phdr->p_filesz > fw->size) {
dev_err(dev, "file %s segment %d would be truncated\n",
@ -258,25 +341,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
memcpy(ptr, fw->data + phdr->p_offset, phdr->p_filesz);
} else if (phdr->p_filesz) {
/* Firmware not large enough, load split-out segments */
sprintf(fw_name + fw_name_len - 3, "b%02d", i);
ret = request_firmware_into_buf(&seg_fw, fw_name, dev,
ptr, phdr->p_filesz);
if (ret) {
dev_err(dev, "error %d loading %s\n",
ret, fw_name);
ret = mdt_load_split_segment(ptr, phdrs, i, fw_name, dev);
if (ret)
break;
}
if (seg_fw->size != phdr->p_filesz) {
dev_err(dev,
"failed to load segment %d from truncated file %s\n",
i, fw_name);
release_firmware(seg_fw);
ret = -EINVAL;
break;
}
release_firmware(seg_fw);
}
if (phdr->p_memsz > phdr->p_filesz)
@ -286,9 +353,6 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
if (reloc_base)
*reloc_base = mem_reloc;
out:
kfree(fw_name);
return ret;
}
@ -310,6 +374,12 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw,
phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base)
{
int ret;
ret = qcom_mdt_pas_init(dev, fw, firmware, pas_id, mem_phys, NULL);
if (ret)
return ret;
return __qcom_mdt_load(dev, fw, firmware, pas_id, mem_region, mem_phys,
mem_size, reloc_base, true);
}

View file

@ -206,6 +206,7 @@ struct ocmem *of_get_ocmem(struct device *dev)
ocmem = platform_get_drvdata(pdev);
if (!ocmem) {
dev_err(dev, "Cannot get ocmem\n");
put_device(&pdev->dev);
return ERR_PTR(-ENODEV);
}
return ocmem;

View file

@ -451,7 +451,11 @@ struct qmp *qmp_get(struct device *dev)
qmp = platform_get_drvdata(pdev);
return qmp ? qmp : ERR_PTR(-EPROBE_DEFER);
if (!qmp) {
put_device(&pdev->dev);
return ERR_PTR(-EPROBE_DEFER);
}
return qmp;
}
EXPORT_SYMBOL(qmp_get);
@ -497,7 +501,7 @@ static int qmp_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, irq, qmp_intr, IRQF_ONESHOT,
ret = devm_request_irq(&pdev->dev, irq, qmp_intr, 0,
"aoss-qmp", qmp);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request interrupt\n");

View file

@ -138,6 +138,22 @@ static const struct rpmpd_desc mdm9607_desc = {
.max_state = RPM_SMD_LEVEL_TURBO,
};
/* msm8226 RPM Power Domains */
DEFINE_RPMPD_PAIR(msm8226, vddcx, vddcx_ao, SMPA, CORNER, 1);
DEFINE_RPMPD_VFC(msm8226, vddcx_vfc, SMPA, 1);
static struct rpmpd *msm8226_rpmpds[] = {
[MSM8226_VDDCX] = &msm8226_vddcx,
[MSM8226_VDDCX_AO] = &msm8226_vddcx_ao,
[MSM8226_VDDCX_VFC] = &msm8226_vddcx_vfc,
};
static const struct rpmpd_desc msm8226_desc = {
.rpmpds = msm8226_rpmpds,
.num_pds = ARRAY_SIZE(msm8226_rpmpds),
.max_state = MAX_CORNER_RPMPD_STATE,
};
/* msm8939 RPM Power Domains */
DEFINE_RPMPD_PAIR(msm8939, vddmd, vddmd_ao, SMPA, CORNER, 1);
DEFINE_RPMPD_VFC(msm8939, vddmd_vfc, SMPA, 1);
@ -436,6 +452,7 @@ static const struct rpmpd_desc qcm2290_desc = {
static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
{ .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
{ .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
{ .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
{ .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc },
@ -610,6 +627,9 @@ static int rpmpd_probe(struct platform_device *pdev)
data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains),
GFP_KERNEL);
if (!data->domains)
return -ENOMEM;
data->num_domains = num;
for (i = 0; i < num; i++) {

View file

@ -104,6 +104,14 @@ static const char *const pmic_models[] = {
[36] = "PM8009",
[38] = "PM8150C",
[41] = "SMB2351",
[47] = "PMK8350",
[48] = "PM8350",
[49] = "PM8350C",
[50] = "PM8350B",
[51] = "PMR735A",
[52] = "PMR735B",
[58] = "PM8450",
[65] = "PM8010",
};
#endif /* CONFIG_DEBUG_FS */
@ -314,10 +322,14 @@ static const struct soc_id soc_id[] = {
{ 422, "IPQ6010" },
{ 425, "SC7180" },
{ 434, "SM6350" },
{ 439, "SM8350" },
{ 449, "SC8280XP" },
{ 453, "IPQ6005" },
{ 455, "QRB5165" },
{ 457, "SM8450" },
{ 459, "SM7225" },
{ 460, "SA8540P" },
{ 480, "SM8450" },
};
static const char *socinfo_machine(struct device *dev, unsigned int id)

View file

@ -139,6 +139,11 @@
#define MDM9607_VDDMX_AO 4
#define MDM9607_VDDMX_VFL 5
/* MSM8226 Power Domain Indexes */
#define MSM8226_VDDCX 0
#define MSM8226_VDDCX_AO 1
#define MSM8226_VDDCX_VFC 2
/* MSM8939 Power Domains */
#define MSM8939_VDDMDCX 0
#define MSM8939_VDDMDCX_AO 1

View file

@ -63,13 +63,21 @@ enum qcom_scm_ice_cipher {
extern bool qcom_scm_is_available(void);
extern int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus);
extern int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus);
extern int qcom_scm_set_cold_boot_addr(void *entry);
extern int qcom_scm_set_warm_boot_addr(void *entry);
extern void qcom_scm_cpu_power_down(u32 flags);
extern int qcom_scm_set_remote_state(u32 state, u32 id);
struct qcom_scm_pas_metadata {
void *ptr;
dma_addr_t phys;
ssize_t size;
};
extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
size_t size);
size_t size,
struct qcom_scm_pas_metadata *ctx);
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx);
extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
phys_addr_t size);
extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
@ -83,6 +91,7 @@ extern bool qcom_scm_restore_sec_cfg_available(void);
extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
extern int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size);
extern int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size,
u32 cp_nonpixel_start,
u32 cp_nonpixel_size);
@ -107,6 +116,7 @@ extern bool qcom_scm_hdcp_available(void);
extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp);
extern int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt);
extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
extern int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val,

View file

@ -35,7 +35,12 @@
#define LLCC_WRCACHE 31
#define LLCC_CVPFW 32
#define LLCC_CPUSS1 33
#define LLCC_CAMEXP0 34
#define LLCC_CPUMTE 35
#define LLCC_CPUHWT 36
#define LLCC_MDMCLAD2 37
#define LLCC_CAMEXP1 38
#define LLCC_AENPU 45
/**
* struct llcc_slice_desc - Cache slice descriptor
@ -83,7 +88,7 @@ struct llcc_edac_reg_data {
* @bitmap: Bit map to track the active slice ids
* @offsets: Pointer to the bank offsets array
* @ecc_irq: interrupt for llcc cache error detection and reporting
* @major_version: Indicates the LLCC major version
* @version: Indicates the LLCC version
*/
struct llcc_drv_data {
struct regmap *regmap;
@ -96,7 +101,7 @@ struct llcc_drv_data {
unsigned long *bitmap;
u32 *offsets;
int ecc_irq;
u32 major_version;
u32 version;
};
#if IS_ENABLED(CONFIG_QCOM_LLCC)

View file

@ -10,10 +10,14 @@
struct device;
struct firmware;
struct qcom_scm_pas_metadata;
#if IS_ENABLED(CONFIG_QCOM_MDT_LOADER)
ssize_t qcom_mdt_get_size(const struct firmware *fw);
int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, phys_addr_t mem_phys,
struct qcom_scm_pas_metadata *pas_metadata_ctx);
int qcom_mdt_load(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, void *mem_region,
phys_addr_t mem_phys, size_t mem_size,
@ -23,7 +27,8 @@ int qcom_mdt_load_no_init(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, void *mem_region,
phys_addr_t mem_phys, size_t mem_size,
phys_addr_t *reloc_base);
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len);
void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
const char *fw_name, struct device *dev);
#else /* !IS_ENABLED(CONFIG_QCOM_MDT_LOADER) */
@ -32,6 +37,13 @@ static inline ssize_t qcom_mdt_get_size(const struct firmware *fw)
return -ENODEV;
}
static inline int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id, phys_addr_t mem_phys,
struct qcom_scm_pas_metadata *pas_metadata_ctx)
{
return -ENODEV;
}
static inline int qcom_mdt_load(struct device *dev, const struct firmware *fw,
const char *fw_name, int pas_id,
void *mem_region, phys_addr_t mem_phys,
@ -51,7 +63,8 @@ static inline int qcom_mdt_load_no_init(struct device *dev,
}
static inline void *qcom_mdt_read_metadata(const struct firmware *fw,
size_t *data_len)
size_t *data_len, const char *fw_name,
struct device *dev)
{
return ERR_PTR(-ENODEV);
}