mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 12:44:11 +08:00
More Qualcomm driver updates for v5.16
This introduces the Qualcomm "sleep stats" driver, which aids the efforts of bringing various Qualcomm platforms into low power mode. The SMP2P driver gains support for negotiating the "SSR" feature, which is used to better synchronize some corner cases that might appear as the remoteproc is recovering from a crash. The socinfo driver learns about a few new PMICs. SMEM is updated so that it's possible to put the compatible property directly in the reserved-memory node, to avoid having to have a separate node just pointing to the memory-region. Lastly it fixes some bugs in smp2p, apr, rpmhpd drivers, notably avoiding the issue where powering on a power-domain using rpmhpd while keeping the performance_state at 0 is a nop -----BEGIN PGP SIGNATURE----- iQJPBAABCAA5FiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAmF4C2sbHGJqb3JuLmFu ZGVyc3NvbkBsaW5hcm8ub3JnAAoJEAsfOT8Nma3Fh1YP/0ypyzx3b73Fy4VctNSx fh++iOaoYSd7nB0Syvd/iUAQxPgDofeZaWt4kyHmdYV2oLdYbkWIbsM2NmCV3i9H SM7w0pBx8w/F9V6a3kJ4Mx3gY8mET2c6kCnQkpySgawpj2kjA5U60iad5OhTVI+u Gl9S4F1U2y1ml3V2wbcl0seQ90Huh32w4aGzi1NA+fPRNQqZJ2MSt9H3zn0eONHN Ts7pk3+qsbsd66HY9j6SujQ/AbaedKU3KlHmgPIzPnzbEqzkdL8A2RbrOxSG42/c lW8ACxRVBYeB5ddbXzAcjvTsOxjAE6lxVqRowBi4tePBWrsvNi9MBT1HAtj2kNBK to5Z6Ku9x/Cdh20WnDO2PmLgjBLz2W29qRfaOU5VsxK73PFUTzwz8WKOKtJKMfIe A5Cnzu4xkA7YImMjs+1Cs36dQVB8Wl6khwNw0EqKJrj0oKEli7bfL/gsFgrZmf8J GmHmL4F/23APts6tr3FqxmXA/wGtjkmBCyVZNbECI/hBneyuPOVD6rbXzw6vdkYy FJwFFZWDG2yLhjMY8cTvML2PT3wZQWhL9RjEE0flnmOWc0Dhc3P8ANQqp2mIHFJ9 GTW9Z0rrShQuSczA7SleJYNip3kKGaus2LoY2LCZ/T6p2f/ZWvxGjzTgzhYzOnzm UUeWX7YuJQQA5NZRSmFmXO5l =NTMF -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmF4HCUACgkQmmx57+YA GNlWDA/+MyEDO1GJ+kzpVlasKSgVIwoVl82tBhjLMAu+h0G1KZgBsm+ITTI+d8lf EHI2XJHEcTWBTOVazUjC7QL3rKOPRNL4vePrzeXbJoO0BzKku3b9cxI7OgPQema0 TNU63jWWGvmWWo6CV0PEr2LLO8UZGjTYhTiWWhR9Z0TK5o0kYxNuCAnAmiwp5uOG oDx8QzHoWHugDZuyZ1X9R49pV+20IArf09H3HCVGK8oqkAC9ltofwViKkehIfd1H XqgToU5E2fHaSdpdtjMBoVllE7AtZjkR3jod0qgSBki0BclBLWj4fM0HD4cQQi9u v1BxdnC9Xzka7k7gl9I0s1EVs0kwkSNuB0pEdR8a5O3Z3ODogdzVSoD3ZEbesTmC JlQqtrflyilwxXvufrYmxMPysrJaSQgIPy6eBVPip3t0WqCLBNgMNMhkmFrb1oFo 8CHb9oC8TPhYVlhMuwsnZcVUl89b7tdAz7AkUgq/lccFwiGPRRWwhIKBd/E7GowI K8T82hUpx0L8+inDd53l0tk8Dv4xVxBQ3vneGThQ9jjw8O37+UmhCtK1YrfxiuI+ xkBAo6xbCZFg/Tiw6fMFzqMDUAKOpB+L9cgw0WQ0VjgH26ADxhO91RXsd2X/6pyo 3dnmgcFJJjUmsIqVQvZyACOMI/A+vnNvtPump7gh2VRkxASpc5k= =HxRd -----END PGP SIGNATURE----- Merge tag 'qcom-drivers-for-5.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/drivers More Qualcomm driver updates for v5.16 This introduces the Qualcomm "sleep stats" driver, which aids the efforts of bringing various Qualcomm platforms into low power mode. The SMP2P driver gains support for negotiating the "SSR" feature, which is used to better synchronize some corner cases that might appear as the remoteproc is recovering from a crash. The socinfo driver learns about a few new PMICs. SMEM is updated so that it's possible to put the compatible property directly in the reserved-memory node, to avoid having to have a separate node just pointing to the memory-region. Lastly it fixes some bugs in smp2p, apr, rpmhpd drivers, notably avoiding the issue where powering on a power-domain using rpmhpd while keeping the performance_state at 0 is a nop * tag 'qcom-drivers-for-5.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: firmware: qcom: scm: Don't break compile test on non-ARM platforms soc: qcom: smp2p: Add of_node_put() before goto soc: qcom: apr: Add of_node_put() before return soc: qcom: qcom_stats: Fix client votes offset soc: qcom: rpmhpd: fix sm8350_mxc's peer domain dt-bindings: arm: cpus: Document qcom,msm8916-smp enable-method ARM: qcom: Add qcom,msm8916-smp enable-method identical to MSM8226 firmware: qcom: scm: Add support for MC boot address API soc: qcom: spm: Add 8916 SPM register data dt-bindings: soc: qcom: spm: Document qcom,msm8916-saw2-v3.0-cpu soc: qcom: socinfo: Add PM8150C and SMB2351 models firmware: qcom_scm: Fix error retval in __qcom_scm_is_call_available() soc: qcom: smp2p: add feature negotiation and ssr ack feature support soc: qcom: Add Sleep stats driver dt-bindings: Introduce QCOM Sleep stats bindings soc: qcom: socinfo: add two missing PMIC IDs soc: qcom: rpmhpd: Make power_on actually enable the domain soc: qcom: smem: Support reserved-memory description dt-bindings: soc: smem: Make indirection optional dt-bindings: sram: Document qcom,rpm-msg-ram Link: https://lore.kernel.org/r/20211026140706.1205989-1-bjorn.andersson@linaro.org Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
e2a3495bf9
@ -210,6 +210,8 @@ properties:
|
||||
- qcom,kpss-acc-v1
|
||||
- qcom,kpss-acc-v2
|
||||
- qcom,msm8226-smp
|
||||
# Only valid on ARM 32-bit, see above for ARM v8 64-bit
|
||||
- qcom,msm8916-smp
|
||||
- renesas,apmu
|
||||
- renesas,r9a06g032-smp
|
||||
- rockchip,rk3036-smp
|
||||
@ -294,7 +296,8 @@ properties:
|
||||
Specifies the ACC* node associated with this CPU.
|
||||
|
||||
Required for systems that have an "enable-method" property
|
||||
value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2" or "qcom,msm8226-smp"
|
||||
value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2", "qcom,msm8226-smp" or
|
||||
"qcom,msm8916-smp".
|
||||
|
||||
* arm/msm/qcom,kpss-acc.txt
|
||||
|
||||
|
@ -10,14 +10,18 @@ maintainers:
|
||||
- Andy Gross <agross@kernel.org>
|
||||
- Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
|
||||
description: |
|
||||
This binding describes the Qualcomm Shared Memory Manager, used to share data
|
||||
between various subsystems and OSes in Qualcomm platforms.
|
||||
description:
|
||||
This binding describes the Qualcomm Shared Memory Manager, a region of
|
||||
reserved-memory used to share data between various subsystems and OSes in
|
||||
Qualcomm platforms.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,smem
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
memory-region:
|
||||
maxItems: 1
|
||||
description: handle to memory reservation for main SMEM memory region.
|
||||
@ -29,11 +33,19 @@ properties:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: handle to RPM message memory resource
|
||||
|
||||
no-map: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- memory-region
|
||||
- hwlocks
|
||||
|
||||
oneOf:
|
||||
- required:
|
||||
- reg
|
||||
- no-map
|
||||
- required:
|
||||
- memory-region
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
@ -43,6 +55,20 @@ examples:
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
smem@fa00000 {
|
||||
compatible = "qcom,smem";
|
||||
reg = <0xfa00000 0x200000>;
|
||||
no-map;
|
||||
|
||||
hwlocks = <&tcsr_mutex 3>;
|
||||
};
|
||||
};
|
||||
- |
|
||||
reserved-memory {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
smem_region: smem@fa00000 {
|
||||
reg = <0xfa00000 0x200000>;
|
||||
no-map;
|
||||
|
@ -22,6 +22,7 @@ properties:
|
||||
- qcom,sdm660-silver-saw2-v4.1-l2
|
||||
- qcom,msm8998-gold-saw2-v4.1-l2
|
||||
- qcom,msm8998-silver-saw2-v4.1-l2
|
||||
- qcom,msm8916-saw2-v3.0-cpu
|
||||
- qcom,msm8226-saw2-v2.1-cpu
|
||||
- qcom,msm8974-saw2-v2.1-cpu
|
||||
- qcom,apq8084-saw2-v2.1-cpu
|
||||
|
47
Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml
Normal file
47
Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml
Normal file
@ -0,0 +1,47 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/soc/qcom/qcom-stats.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies, Inc. (QTI) Stats bindings
|
||||
|
||||
maintainers:
|
||||
- Maulik Shah <mkshah@codeaurora.org>
|
||||
|
||||
description:
|
||||
Always On Processor/Resource Power Manager maintains statistics of the SoC
|
||||
sleep modes involving powering down of the rails and oscillator clock.
|
||||
|
||||
Statistics includes SoC sleep mode type, number of times low power mode were
|
||||
entered, time of last entry, time of last exit and accumulated sleep duration.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,rpmh-stats
|
||||
- qcom,rpm-stats
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# Example of rpmh sleep stats
|
||||
- |
|
||||
sram@c3f0000 {
|
||||
compatible = "qcom,rpmh-stats";
|
||||
reg = <0x0c3f0000 0x400>;
|
||||
};
|
||||
# Example of rpm sleep stats
|
||||
- |
|
||||
sram@4690000 {
|
||||
compatible = "qcom,rpm-stats";
|
||||
reg = <0x04690000 0x10000>;
|
||||
};
|
||||
...
|
@ -31,6 +31,7 @@ properties:
|
||||
- amlogic,meson-gxbb-sram
|
||||
- arm,juno-sram-ns
|
||||
- atmel,sama5d2-securam
|
||||
- qcom,rpm-msg-ram
|
||||
- rockchip,rk3288-pmu-sram
|
||||
|
||||
reg:
|
||||
@ -135,7 +136,9 @@ if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: rockchip,rk3288-pmu-sram
|
||||
enum:
|
||||
- qcom,rpm-msg-ram
|
||||
- rockchip,rk3288-pmu-sram
|
||||
|
||||
else:
|
||||
required:
|
||||
|
@ -385,6 +385,7 @@ static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = {
|
||||
#endif
|
||||
};
|
||||
CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops);
|
||||
CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops);
|
||||
|
||||
static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
|
||||
.smp_prepare_cpus = qcom_smp_prepare_cpus,
|
||||
|
@ -17,6 +17,10 @@
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
|
||||
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
|
||||
#include <asm/smp_plat.h>
|
||||
#endif
|
||||
|
||||
#include "qcom_scm.h"
|
||||
|
||||
static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT);
|
||||
@ -252,7 +256,7 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
|
||||
break;
|
||||
default:
|
||||
pr_err("Unknown SMC convention being used\n");
|
||||
return -EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = qcom_scm_call(dev, &desc, &res);
|
||||
@ -260,15 +264,44 @@ 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)
|
||||
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
|
||||
static int __qcom_scm_set_boot_addr_mc(void *entry, const cpumask_t *cpus,
|
||||
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),
|
||||
};
|
||||
unsigned int cpu;
|
||||
u64 map;
|
||||
|
||||
/* Need a device for DMA of the additional arguments */
|
||||
if (!__scm || __get_convention() == SMC_CONVENTION_LEGACY)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
desc.args[0] = virt_to_phys(entry);
|
||||
for_each_cpu(cpu, cpus) {
|
||||
map = cpu_logical_map(cpu);
|
||||
desc.args[1] |= BIT(MPIDR_AFFINITY_LEVEL(map, 0));
|
||||
desc.args[2] |= BIT(MPIDR_AFFINITY_LEVEL(map, 1));
|
||||
desc.args[3] |= BIT(MPIDR_AFFINITY_LEVEL(map, 2));
|
||||
}
|
||||
desc.args[4] = ~0ULL; /* Reserved for affinity level 3 */
|
||||
desc.args[5] = flags;
|
||||
|
||||
return qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
}
|
||||
#else
|
||||
static inline int __qcom_scm_set_boot_addr_mc(void *entry, const cpumask_t *cpus,
|
||||
unsigned int flags)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
|
||||
{
|
||||
int ret;
|
||||
int flags = 0;
|
||||
@ -304,17 +337,28 @@ int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
|
||||
|
||||
/**
|
||||
* qcom_scm_set_cold_boot_addr() - Set the cold boot address for cpus
|
||||
* 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 cold boot address of the cpus. Any cpu outside the supported
|
||||
* range would be removed from the cpu present mask.
|
||||
* 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_cold_boot_addr(void *entry, const cpumask_t *cpus)
|
||||
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
|
||||
{
|
||||
if (!cpus || cpumask_empty(cpus))
|
||||
return -EINVAL;
|
||||
|
||||
if (__qcom_scm_set_boot_addr_mc(entry, cpus, QCOM_SCM_BOOT_MC_FLAG_WARMBOOT))
|
||||
/* Fallback to old SCM call */
|
||||
return __qcom_scm_set_warm_boot_addr(entry, cpus);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr);
|
||||
|
||||
static int __qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
|
||||
{
|
||||
int flags = 0;
|
||||
int cpu;
|
||||
@ -331,9 +375,6 @@ 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];
|
||||
@ -346,6 +387,25 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
|
||||
|
||||
return qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (!cpus || cpumask_empty(cpus))
|
||||
return -EINVAL;
|
||||
|
||||
if (__qcom_scm_set_boot_addr_mc(entry, cpus, QCOM_SCM_BOOT_MC_FLAG_COLDBOOT))
|
||||
/* Fallback to old SCM call */
|
||||
return __qcom_scm_set_cold_boot_addr(entry, cpus);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr);
|
||||
|
||||
/**
|
||||
|
@ -78,8 +78,12 @@ 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_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
|
||||
|
@ -509,6 +509,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_populate);
|
||||
static const struct of_device_id reserved_mem_matches[] = {
|
||||
{ .compatible = "qcom,rmtfs-mem" },
|
||||
{ .compatible = "qcom,cmd-db" },
|
||||
{ .compatible = "qcom,smem" },
|
||||
{ .compatible = "ramoops" },
|
||||
{ .compatible = "nvmem-rmem" },
|
||||
{}
|
||||
|
@ -199,6 +199,16 @@ config QCOM_SPM
|
||||
to manage cores, L2 low power modes and to configure the internal
|
||||
Adaptive Voltage Scaler parameters, where supported.
|
||||
|
||||
config QCOM_STATS
|
||||
tristate "Qualcomm Technologies, Inc. (QTI) Sleep stats driver"
|
||||
depends on (ARCH_QCOM && DEBUG_FS) || COMPILE_TEST
|
||||
depends on QCOM_SMEM
|
||||
help
|
||||
Qualcomm Technologies, Inc. (QTI) Sleep stats driver to read
|
||||
the shared memory exported by the remote processor related to
|
||||
various SoC level low power modes statistics and export to debugfs
|
||||
interface.
|
||||
|
||||
config QCOM_WCNSS_CTRL
|
||||
tristate "Qualcomm WCNSS control driver"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
|
@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
|
||||
obj-$(CONFIG_QCOM_SMSM) += smsm.o
|
||||
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
|
||||
obj-$(CONFIG_QCOM_SPM) += spm.o
|
||||
obj-$(CONFIG_QCOM_STATS) += qcom_stats.o
|
||||
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
|
||||
obj-$(CONFIG_QCOM_APR) += apr.o
|
||||
obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
|
||||
|
@ -492,12 +492,14 @@ static int of_apr_add_pd_lookups(struct device *dev)
|
||||
1, &service_path);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "pdr service path missing: %d\n", ret);
|
||||
of_node_put(node);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pds = pdr_add_lookup(apr->pdr, service_name, service_path);
|
||||
if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
|
||||
dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds));
|
||||
of_node_put(node);
|
||||
return PTR_ERR(pds);
|
||||
}
|
||||
}
|
||||
|
277
drivers/soc/qcom/qcom_stats.c
Normal file
277
drivers/soc/qcom/qcom_stats.c
Normal file
@ -0,0 +1,277 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <linux/soc/qcom/smem.h>
|
||||
#include <clocksource/arm_arch_timer.h>
|
||||
|
||||
#define RPM_DYNAMIC_ADDR 0x14
|
||||
#define RPM_DYNAMIC_ADDR_MASK 0xFFFF
|
||||
|
||||
#define STAT_TYPE_OFFSET 0x0
|
||||
#define COUNT_OFFSET 0x4
|
||||
#define LAST_ENTERED_AT_OFFSET 0x8
|
||||
#define LAST_EXITED_AT_OFFSET 0x10
|
||||
#define ACCUMULATED_OFFSET 0x18
|
||||
#define CLIENT_VOTES_OFFSET 0x20
|
||||
|
||||
struct subsystem_data {
|
||||
const char *name;
|
||||
u32 smem_item;
|
||||
u32 pid;
|
||||
};
|
||||
|
||||
static const struct subsystem_data subsystems[] = {
|
||||
{ "modem", 605, 1 },
|
||||
{ "wpss", 605, 13 },
|
||||
{ "adsp", 606, 2 },
|
||||
{ "cdsp", 607, 5 },
|
||||
{ "slpi", 608, 3 },
|
||||
{ "gpu", 609, 0 },
|
||||
{ "display", 610, 0 },
|
||||
{ "adsp_island", 613, 2 },
|
||||
{ "slpi_island", 613, 3 },
|
||||
};
|
||||
|
||||
struct stats_config {
|
||||
size_t stats_offset;
|
||||
size_t num_records;
|
||||
bool appended_stats_avail;
|
||||
bool dynamic_offset;
|
||||
bool subsystem_stats_in_smem;
|
||||
};
|
||||
|
||||
struct stats_data {
|
||||
bool appended_stats_avail;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
struct sleep_stats {
|
||||
u32 stat_type;
|
||||
u32 count;
|
||||
u64 last_entered_at;
|
||||
u64 last_exited_at;
|
||||
u64 accumulated;
|
||||
};
|
||||
|
||||
struct appended_stats {
|
||||
u32 client_votes;
|
||||
u32 reserved[3];
|
||||
};
|
||||
|
||||
static void qcom_print_stats(struct seq_file *s, const struct sleep_stats *stat)
|
||||
{
|
||||
u64 accumulated = stat->accumulated;
|
||||
/*
|
||||
* If a subsystem is in sleep when reading the sleep stats adjust
|
||||
* the accumulated sleep duration to show actual sleep time.
|
||||
*/
|
||||
if (stat->last_entered_at > stat->last_exited_at)
|
||||
accumulated += arch_timer_read_counter() - stat->last_entered_at;
|
||||
|
||||
seq_printf(s, "Count: %u\n", stat->count);
|
||||
seq_printf(s, "Last Entered At: %llu\n", stat->last_entered_at);
|
||||
seq_printf(s, "Last Exited At: %llu\n", stat->last_exited_at);
|
||||
seq_printf(s, "Accumulated Duration: %llu\n", accumulated);
|
||||
}
|
||||
|
||||
static int qcom_subsystem_sleep_stats_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct subsystem_data *subsystem = s->private;
|
||||
struct sleep_stats *stat;
|
||||
|
||||
/* Items are allocated lazily, so lookup pointer each time */
|
||||
stat = qcom_smem_get(subsystem->pid, subsystem->smem_item, NULL);
|
||||
if (IS_ERR(stat))
|
||||
return -EIO;
|
||||
|
||||
qcom_print_stats(s, stat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct stats_data *d = s->private;
|
||||
void __iomem *reg = d->base;
|
||||
struct sleep_stats stat;
|
||||
|
||||
memcpy_fromio(&stat, reg, sizeof(stat));
|
||||
qcom_print_stats(s, &stat);
|
||||
|
||||
if (d->appended_stats_avail) {
|
||||
struct appended_stats votes;
|
||||
|
||||
memcpy_fromio(&votes, reg + CLIENT_VOTES_OFFSET, sizeof(votes));
|
||||
seq_printf(s, "Client Votes: %#x\n", votes.client_votes);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(qcom_soc_sleep_stats);
|
||||
DEFINE_SHOW_ATTRIBUTE(qcom_subsystem_sleep_stats);
|
||||
|
||||
static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *reg,
|
||||
struct stats_data *d,
|
||||
const struct stats_config *config)
|
||||
{
|
||||
char stat_type[sizeof(u32) + 1] = {0};
|
||||
size_t stats_offset = config->stats_offset;
|
||||
u32 offset = 0, type;
|
||||
int i, j;
|
||||
|
||||
/*
|
||||
* On RPM targets, stats offset location is dynamic and changes from target
|
||||
* to target and sometimes from build to build for same target.
|
||||
*
|
||||
* In such cases the dynamic address is present at 0x14 offset from base
|
||||
* address in devicetree. The last 16bits indicates the stats_offset.
|
||||
*/
|
||||
if (config->dynamic_offset) {
|
||||
stats_offset = readl(reg + RPM_DYNAMIC_ADDR);
|
||||
stats_offset &= RPM_DYNAMIC_ADDR_MASK;
|
||||
}
|
||||
|
||||
for (i = 0; i < config->num_records; i++) {
|
||||
d[i].base = reg + offset + stats_offset;
|
||||
|
||||
/*
|
||||
* Read the low power mode name and create debugfs file for it.
|
||||
* The names read could be of below,
|
||||
* (may change depending on low power mode supported).
|
||||
* For rpmh-sleep-stats: "aosd", "cxsd" and "ddr".
|
||||
* For rpm-sleep-stats: "vmin" and "vlow".
|
||||
*/
|
||||
type = readl(d[i].base);
|
||||
for (j = 0; j < sizeof(u32); j++) {
|
||||
stat_type[j] = type & 0xff;
|
||||
type = type >> 8;
|
||||
}
|
||||
strim(stat_type);
|
||||
debugfs_create_file(stat_type, 0400, root, &d[i],
|
||||
&qcom_soc_sleep_stats_fops);
|
||||
|
||||
offset += sizeof(struct sleep_stats);
|
||||
if (d[i].appended_stats_avail)
|
||||
offset += sizeof(struct appended_stats);
|
||||
}
|
||||
}
|
||||
|
||||
static void qcom_create_subsystem_stat_files(struct dentry *root,
|
||||
const struct stats_config *config)
|
||||
{
|
||||
const struct sleep_stats *stat;
|
||||
int i;
|
||||
|
||||
if (!config->subsystem_stats_in_smem)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(subsystems); i++) {
|
||||
stat = qcom_smem_get(subsystems[i].pid, subsystems[i].smem_item, NULL);
|
||||
if (IS_ERR(stat))
|
||||
continue;
|
||||
|
||||
debugfs_create_file(subsystems[i].name, 0400, root, (void *)&subsystems[i],
|
||||
&qcom_subsystem_sleep_stats_fops);
|
||||
}
|
||||
}
|
||||
|
||||
static int qcom_stats_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *reg;
|
||||
struct dentry *root;
|
||||
const struct stats_config *config;
|
||||
struct stats_data *d;
|
||||
int i;
|
||||
|
||||
config = device_get_match_data(&pdev->dev);
|
||||
if (!config)
|
||||
return -ENODEV;
|
||||
|
||||
reg = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||
if (IS_ERR(reg))
|
||||
return -ENOMEM;
|
||||
|
||||
d = devm_kcalloc(&pdev->dev, config->num_records,
|
||||
sizeof(*d), GFP_KERNEL);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < config->num_records; i++)
|
||||
d[i].appended_stats_avail = config->appended_stats_avail;
|
||||
|
||||
root = debugfs_create_dir("qcom_stats", NULL);
|
||||
|
||||
qcom_create_subsystem_stat_files(root, config);
|
||||
qcom_create_soc_sleep_stat_files(root, reg, d, config);
|
||||
|
||||
platform_set_drvdata(pdev, root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_stats_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dentry *root = platform_get_drvdata(pdev);
|
||||
|
||||
debugfs_remove_recursive(root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct stats_config rpm_data = {
|
||||
.stats_offset = 0,
|
||||
.num_records = 2,
|
||||
.appended_stats_avail = true,
|
||||
.dynamic_offset = true,
|
||||
.subsystem_stats_in_smem = false,
|
||||
};
|
||||
|
||||
static const struct stats_config rpmh_data = {
|
||||
.stats_offset = 0x48,
|
||||
.num_records = 3,
|
||||
.appended_stats_avail = false,
|
||||
.dynamic_offset = false,
|
||||
.subsystem_stats_in_smem = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_stats_table[] = {
|
||||
{ .compatible = "qcom,rpm-stats", .data = &rpm_data },
|
||||
{ .compatible = "qcom,rpmh-stats", .data = &rpmh_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_stats_table);
|
||||
|
||||
static struct platform_driver qcom_stats = {
|
||||
.probe = qcom_stats_probe,
|
||||
.remove = qcom_stats_remove,
|
||||
.driver = {
|
||||
.name = "qcom_stats",
|
||||
.of_match_table = qcom_stats_table,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init qcom_stats_init(void)
|
||||
{
|
||||
return platform_driver_register(&qcom_stats);
|
||||
}
|
||||
late_initcall(qcom_stats_init);
|
||||
|
||||
static void __exit qcom_stats_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&qcom_stats);
|
||||
}
|
||||
module_exit(qcom_stats_exit)
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. (QTI) Stats driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -30,6 +30,7 @@
|
||||
* @active_only: True if it represents an Active only peer
|
||||
* @corner: current corner
|
||||
* @active_corner: current active corner
|
||||
* @enable_corner: lowest non-zero corner
|
||||
* @level: An array of level (vlvl) to corner (hlvl) mappings
|
||||
* derived from cmd-db
|
||||
* @level_count: Number of levels supported by the power domain. max
|
||||
@ -47,6 +48,7 @@ struct rpmhpd {
|
||||
const bool active_only;
|
||||
unsigned int corner;
|
||||
unsigned int active_corner;
|
||||
unsigned int enable_corner;
|
||||
u32 level[RPMH_ARC_MAX_LEVELS];
|
||||
size_t level_count;
|
||||
bool enabled;
|
||||
@ -219,7 +221,7 @@ static const struct rpmhpd_desc sm8250_desc = {
|
||||
static struct rpmhpd sm8350_mxc_ao;
|
||||
static struct rpmhpd sm8350_mxc = {
|
||||
.pd = { .name = "mxc", },
|
||||
.peer = &sm8150_mmcx_ao,
|
||||
.peer = &sm8350_mxc_ao,
|
||||
.res_name = "mxc.lvl",
|
||||
};
|
||||
|
||||
@ -401,13 +403,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner)
|
||||
static int rpmhpd_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct rpmhpd *pd = domain_to_rpmhpd(domain);
|
||||
int ret = 0;
|
||||
unsigned int corner;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&rpmhpd_lock);
|
||||
|
||||
if (pd->corner)
|
||||
ret = rpmhpd_aggregate_corner(pd, pd->corner);
|
||||
|
||||
corner = max(pd->corner, pd->enable_corner);
|
||||
ret = rpmhpd_aggregate_corner(pd, corner);
|
||||
if (!ret)
|
||||
pd->enabled = true;
|
||||
|
||||
@ -452,6 +454,10 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
|
||||
i--;
|
||||
|
||||
if (pd->enabled) {
|
||||
/* Ensure that the domain isn't turn off */
|
||||
if (i < pd->enable_corner)
|
||||
i = pd->enable_corner;
|
||||
|
||||
ret = rpmhpd_aggregate_corner(pd, i);
|
||||
if (ret)
|
||||
goto out;
|
||||
@ -488,6 +494,10 @@ static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
|
||||
for (i = 0; i < rpmhpd->level_count; i++) {
|
||||
rpmhpd->level[i] = buf[i];
|
||||
|
||||
/* Remember the first corner with non-zero level */
|
||||
if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i])
|
||||
rpmhpd->enable_corner = i;
|
||||
|
||||
/*
|
||||
* The AUX data may be zero padded. These 0 valued entries at
|
||||
* the end of the map must be ignored.
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/slab.h>
|
||||
@ -240,7 +241,7 @@ static const u8 SMEM_INFO_MAGIC[] = { 0x53, 0x49, 0x49, 0x49 }; /* SIII */
|
||||
* @size: size of the memory region
|
||||
*/
|
||||
struct smem_region {
|
||||
u32 aux_base;
|
||||
phys_addr_t aux_base;
|
||||
void __iomem *virt_base;
|
||||
size_t size;
|
||||
};
|
||||
@ -499,7 +500,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
|
||||
for (i = 0; i < smem->num_regions; i++) {
|
||||
region = &smem->regions[i];
|
||||
|
||||
if (region->aux_base == aux_base || !aux_base) {
|
||||
if ((u32)region->aux_base == aux_base || !aux_base) {
|
||||
if (size != NULL)
|
||||
*size = le32_to_cpu(entry->size);
|
||||
return region->virt_base + le32_to_cpu(entry->offset);
|
||||
@ -664,7 +665,7 @@ phys_addr_t qcom_smem_virt_to_phys(void *p)
|
||||
if (p < region->virt_base + region->size) {
|
||||
u64 offset = p - region->virt_base;
|
||||
|
||||
return (phys_addr_t)region->aux_base + offset;
|
||||
return region->aux_base + offset;
|
||||
}
|
||||
}
|
||||
|
||||
@ -863,12 +864,12 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
|
||||
const char *name, int i)
|
||||
static int qcom_smem_resolve_mem(struct qcom_smem *smem, const char *name,
|
||||
struct smem_region *region)
|
||||
{
|
||||
struct device *dev = smem->dev;
|
||||
struct device_node *np;
|
||||
struct resource r;
|
||||
resource_size_t size;
|
||||
int ret;
|
||||
|
||||
np = of_parse_phandle(dev->of_node, name, 0);
|
||||
@ -881,13 +882,9 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
|
||||
of_node_put(np);
|
||||
if (ret)
|
||||
return ret;
|
||||
size = resource_size(&r);
|
||||
|
||||
smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size);
|
||||
if (!smem->regions[i].virt_base)
|
||||
return -ENOMEM;
|
||||
smem->regions[i].aux_base = (u32)r.start;
|
||||
smem->regions[i].size = size;
|
||||
region->aux_base = r.start;
|
||||
region->size = resource_size(&r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -895,12 +892,14 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
|
||||
static int qcom_smem_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct smem_header *header;
|
||||
struct reserved_mem *rmem;
|
||||
struct qcom_smem *smem;
|
||||
size_t array_size;
|
||||
int num_regions;
|
||||
int hwlock_id;
|
||||
u32 version;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
num_regions = 1;
|
||||
if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL))
|
||||
@ -914,13 +913,35 @@ static int qcom_smem_probe(struct platform_device *pdev)
|
||||
smem->dev = &pdev->dev;
|
||||
smem->num_regions = num_regions;
|
||||
|
||||
ret = qcom_smem_map_memory(smem, &pdev->dev, "memory-region", 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
rmem = of_reserved_mem_lookup(pdev->dev.of_node);
|
||||
if (rmem) {
|
||||
smem->regions[0].aux_base = rmem->base;
|
||||
smem->regions[0].size = rmem->size;
|
||||
} else {
|
||||
/*
|
||||
* Fall back to the memory-region reference, if we're not a
|
||||
* reserved-memory node.
|
||||
*/
|
||||
ret = qcom_smem_resolve_mem(smem, "memory-region", &smem->regions[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (num_regions > 1 && (ret = qcom_smem_map_memory(smem, &pdev->dev,
|
||||
"qcom,rpm-msg-ram", 1)))
|
||||
return ret;
|
||||
if (num_regions > 1) {
|
||||
ret = qcom_smem_resolve_mem(smem, "qcom,rpm-msg-ram", &smem->regions[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_regions; i++) {
|
||||
smem->regions[i].virt_base = devm_ioremap_wc(&pdev->dev,
|
||||
smem->regions[i].aux_base,
|
||||
smem->regions[i].size);
|
||||
if (!smem->regions[i].virt_base) {
|
||||
dev_err(&pdev->dev, "failed to remap %pa\n", &smem->regions[i].aux_base);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
header = smem->regions[0].virt_base;
|
||||
if (le32_to_cpu(header->initialized) != 1 ||
|
||||
|
@ -41,8 +41,11 @@
|
||||
#define SMP2P_MAX_ENTRY_NAME 16
|
||||
|
||||
#define SMP2P_FEATURE_SSR_ACK 0x1
|
||||
#define SMP2P_FLAGS_RESTART_DONE_BIT 0
|
||||
#define SMP2P_FLAGS_RESTART_ACK_BIT 1
|
||||
|
||||
#define SMP2P_MAGIC 0x504d5324
|
||||
#define SMP2P_ALL_FEATURES SMP2P_FEATURE_SSR_ACK
|
||||
|
||||
/**
|
||||
* struct smp2p_smem_item - in memory communication structure
|
||||
@ -136,6 +139,10 @@ struct qcom_smp2p {
|
||||
|
||||
unsigned valid_entries;
|
||||
|
||||
bool ssr_ack_enabled;
|
||||
bool ssr_ack;
|
||||
bool negotiation_done;
|
||||
|
||||
unsigned local_pid;
|
||||
unsigned remote_pid;
|
||||
|
||||
@ -163,22 +170,53 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_smp2p_intr() - interrupt handler for incoming notifications
|
||||
* @irq: unused
|
||||
* @data: smp2p driver context
|
||||
*
|
||||
* Handle notifications from the remote side to handle newly allocated entries
|
||||
* or any changes to the state bits of existing entries.
|
||||
*/
|
||||
static irqreturn_t qcom_smp2p_intr(int irq, void *data)
|
||||
static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p)
|
||||
{
|
||||
struct smp2p_smem_item *in = smp2p->in;
|
||||
bool restart;
|
||||
|
||||
if (!smp2p->ssr_ack_enabled)
|
||||
return false;
|
||||
|
||||
restart = in->flags & BIT(SMP2P_FLAGS_RESTART_DONE_BIT);
|
||||
|
||||
return restart != smp2p->ssr_ack;
|
||||
}
|
||||
|
||||
static void qcom_smp2p_do_ssr_ack(struct qcom_smp2p *smp2p)
|
||||
{
|
||||
struct smp2p_smem_item *out = smp2p->out;
|
||||
u32 val;
|
||||
|
||||
smp2p->ssr_ack = !smp2p->ssr_ack;
|
||||
|
||||
val = out->flags & ~BIT(SMP2P_FLAGS_RESTART_ACK_BIT);
|
||||
if (smp2p->ssr_ack)
|
||||
val |= BIT(SMP2P_FLAGS_RESTART_ACK_BIT);
|
||||
out->flags = val;
|
||||
|
||||
qcom_smp2p_kick(smp2p);
|
||||
}
|
||||
|
||||
static void qcom_smp2p_negotiate(struct qcom_smp2p *smp2p)
|
||||
{
|
||||
struct smp2p_smem_item *out = smp2p->out;
|
||||
struct smp2p_smem_item *in = smp2p->in;
|
||||
|
||||
if (in->version == out->version) {
|
||||
out->features &= in->features;
|
||||
|
||||
if (out->features & SMP2P_FEATURE_SSR_ACK)
|
||||
smp2p->ssr_ack_enabled = true;
|
||||
|
||||
smp2p->negotiation_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void qcom_smp2p_notify_in(struct qcom_smp2p *smp2p)
|
||||
{
|
||||
struct smp2p_smem_item *in;
|
||||
struct smp2p_entry *entry;
|
||||
struct qcom_smp2p *smp2p = data;
|
||||
unsigned smem_id = smp2p->smem_items[SMP2P_INBOUND];
|
||||
unsigned pid = smp2p->remote_pid;
|
||||
size_t size;
|
||||
int irq_pin;
|
||||
u32 status;
|
||||
char buf[SMP2P_MAX_ENTRY_NAME];
|
||||
@ -187,18 +225,6 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data)
|
||||
|
||||
in = smp2p->in;
|
||||
|
||||
/* Acquire smem item, if not already found */
|
||||
if (!in) {
|
||||
in = qcom_smem_get(pid, smem_id, &size);
|
||||
if (IS_ERR(in)) {
|
||||
dev_err(smp2p->dev,
|
||||
"Unable to acquire remote smp2p item\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
smp2p->in = in;
|
||||
}
|
||||
|
||||
/* Match newly created entries */
|
||||
for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
|
||||
list_for_each_entry(entry, &smp2p->inbound, node) {
|
||||
@ -237,7 +263,51 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_smp2p_intr() - interrupt handler for incoming notifications
|
||||
* @irq: unused
|
||||
* @data: smp2p driver context
|
||||
*
|
||||
* Handle notifications from the remote side to handle newly allocated entries
|
||||
* or any changes to the state bits of existing entries.
|
||||
*/
|
||||
static irqreturn_t qcom_smp2p_intr(int irq, void *data)
|
||||
{
|
||||
struct smp2p_smem_item *in;
|
||||
struct qcom_smp2p *smp2p = data;
|
||||
unsigned int smem_id = smp2p->smem_items[SMP2P_INBOUND];
|
||||
unsigned int pid = smp2p->remote_pid;
|
||||
bool ack_restart;
|
||||
size_t size;
|
||||
|
||||
in = smp2p->in;
|
||||
|
||||
/* Acquire smem item, if not already found */
|
||||
if (!in) {
|
||||
in = qcom_smem_get(pid, smem_id, &size);
|
||||
if (IS_ERR(in)) {
|
||||
dev_err(smp2p->dev,
|
||||
"Unable to acquire remote smp2p item\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
smp2p->in = in;
|
||||
}
|
||||
|
||||
if (!smp2p->negotiation_done)
|
||||
qcom_smp2p_negotiate(smp2p);
|
||||
|
||||
if (smp2p->negotiation_done) {
|
||||
ack_restart = qcom_smp2p_check_ssr(smp2p);
|
||||
qcom_smp2p_notify_in(smp2p);
|
||||
|
||||
if (ack_restart)
|
||||
qcom_smp2p_do_ssr_ack(smp2p);
|
||||
}
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -393,6 +463,7 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p)
|
||||
out->remote_pid = smp2p->remote_pid;
|
||||
out->total_entries = SMP2P_MAX_ENTRY;
|
||||
out->valid_entries = 0;
|
||||
out->features = SMP2P_ALL_FEATURES;
|
||||
|
||||
/*
|
||||
* Make sure the rest of the header is written before we validate the
|
||||
@ -502,6 +573,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
|
||||
entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry) {
|
||||
ret = -ENOMEM;
|
||||
of_node_put(node);
|
||||
goto unwind_interfaces;
|
||||
}
|
||||
|
||||
@ -509,19 +581,25 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&entry->lock);
|
||||
|
||||
ret = of_property_read_string(node, "qcom,entry-name", &entry->name);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
of_node_put(node);
|
||||
goto unwind_interfaces;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(node, "interrupt-controller")) {
|
||||
ret = qcom_smp2p_inbound_entry(smp2p, entry, node);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
of_node_put(node);
|
||||
goto unwind_interfaces;
|
||||
}
|
||||
|
||||
list_add(&entry->node, &smp2p->inbound);
|
||||
} else {
|
||||
ret = qcom_smp2p_outbound_entry(smp2p, entry, node);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
of_node_put(node);
|
||||
goto unwind_interfaces;
|
||||
}
|
||||
|
||||
list_add(&entry->node, &smp2p->outbound);
|
||||
}
|
||||
|
@ -87,8 +87,8 @@ static const char *const pmic_models[] = {
|
||||
[15] = "PM8901",
|
||||
[16] = "PM8950/PM8027",
|
||||
[17] = "PMI8950/ISL9519",
|
||||
[18] = "PM8921",
|
||||
[19] = "PM8018",
|
||||
[18] = "PMK8001/PM8921",
|
||||
[19] = "PMI8996/PM8018",
|
||||
[20] = "PM8998/PM8015",
|
||||
[21] = "PMI8998/PM8014",
|
||||
[22] = "PM8821",
|
||||
@ -102,6 +102,8 @@ static const char *const pmic_models[] = {
|
||||
[32] = "PM8150B",
|
||||
[33] = "PMK8002",
|
||||
[36] = "PM8009",
|
||||
[38] = "PM8150C",
|
||||
[41] = "SMB2351",
|
||||
};
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
|
@ -67,6 +67,25 @@ static const struct spm_reg_data spm_reg_8998_silver_l2 = {
|
||||
.avs_limit = 0x4200420,
|
||||
};
|
||||
|
||||
static const u16 spm_reg_offset_v3_0[SPM_REG_NR] = {
|
||||
[SPM_REG_CFG] = 0x08,
|
||||
[SPM_REG_SPM_CTL] = 0x30,
|
||||
[SPM_REG_DLY] = 0x34,
|
||||
[SPM_REG_SEQ_ENTRY] = 0x400,
|
||||
};
|
||||
|
||||
/* SPM register data for 8916 */
|
||||
static const struct spm_reg_data spm_reg_8916_cpu = {
|
||||
.reg_offset = spm_reg_offset_v3_0,
|
||||
.spm_cfg = 0x1,
|
||||
.spm_dly = 0x3C102800,
|
||||
.seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90,
|
||||
0x5B, 0x60, 0x03, 0x60, 0x3B, 0x76, 0x76, 0x0B, 0x94, 0x5B,
|
||||
0x80, 0x10, 0x26, 0x30, 0x0F },
|
||||
.start_index[PM_SLEEP_MODE_STBY] = 0,
|
||||
.start_index[PM_SLEEP_MODE_SPC] = 5,
|
||||
};
|
||||
|
||||
static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = {
|
||||
[SPM_REG_CFG] = 0x08,
|
||||
[SPM_REG_SPM_CTL] = 0x30,
|
||||
@ -176,6 +195,8 @@ static const struct of_device_id spm_match_table[] = {
|
||||
.data = &spm_reg_660_silver_l2 },
|
||||
{ .compatible = "qcom,msm8226-saw2-v2.1-cpu",
|
||||
.data = &spm_reg_8226_cpu },
|
||||
{ .compatible = "qcom,msm8916-saw2-v3.0-cpu",
|
||||
.data = &spm_reg_8916_cpu },
|
||||
{ .compatible = "qcom,msm8974-saw2-v2.1-cpu",
|
||||
.data = &spm_reg_8974_8084_cpu },
|
||||
{ .compatible = "qcom,msm8998-gold-saw2-v4.1-l2",
|
||||
|
Loading…
Reference in New Issue
Block a user