Commit e2a3495b authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'qcom-drivers-for-5.16-2' of...

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.orgSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 64954d19 c50031f0
...@@ -210,6 +210,8 @@ properties: ...@@ -210,6 +210,8 @@ properties:
- qcom,kpss-acc-v1 - qcom,kpss-acc-v1
- qcom,kpss-acc-v2 - qcom,kpss-acc-v2
- qcom,msm8226-smp - qcom,msm8226-smp
# Only valid on ARM 32-bit, see above for ARM v8 64-bit
- qcom,msm8916-smp
- renesas,apmu - renesas,apmu
- renesas,r9a06g032-smp - renesas,r9a06g032-smp
- rockchip,rk3036-smp - rockchip,rk3036-smp
...@@ -294,7 +296,8 @@ properties: ...@@ -294,7 +296,8 @@ properties:
Specifies the ACC* node associated with this CPU. Specifies the ACC* node associated with this CPU.
Required for systems that have an "enable-method" property 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 * arm/msm/qcom,kpss-acc.txt
......
...@@ -10,14 +10,18 @@ maintainers: ...@@ -10,14 +10,18 @@ maintainers:
- Andy Gross <agross@kernel.org> - Andy Gross <agross@kernel.org>
- Bjorn Andersson <bjorn.andersson@linaro.org> - Bjorn Andersson <bjorn.andersson@linaro.org>
description: | description:
This binding describes the Qualcomm Shared Memory Manager, used to share data This binding describes the Qualcomm Shared Memory Manager, a region of
between various subsystems and OSes in Qualcomm platforms. reserved-memory used to share data between various subsystems and OSes in
Qualcomm platforms.
properties: properties:
compatible: compatible:
const: qcom,smem const: qcom,smem
reg:
maxItems: 1
memory-region: memory-region:
maxItems: 1 maxItems: 1
description: handle to memory reservation for main SMEM memory region. description: handle to memory reservation for main SMEM memory region.
...@@ -29,11 +33,19 @@ properties: ...@@ -29,11 +33,19 @@ properties:
$ref: /schemas/types.yaml#/definitions/phandle $ref: /schemas/types.yaml#/definitions/phandle
description: handle to RPM message memory resource description: handle to RPM message memory resource
no-map: true
required: required:
- compatible - compatible
- memory-region
- hwlocks - hwlocks
oneOf:
- required:
- reg
- no-map
- required:
- memory-region
additionalProperties: false additionalProperties: false
examples: examples:
...@@ -43,6 +55,20 @@ examples: ...@@ -43,6 +55,20 @@ examples:
#size-cells = <1>; #size-cells = <1>;
ranges; 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 { smem_region: smem@fa00000 {
reg = <0xfa00000 0x200000>; reg = <0xfa00000 0x200000>;
no-map; no-map;
......
...@@ -22,6 +22,7 @@ properties: ...@@ -22,6 +22,7 @@ properties:
- qcom,sdm660-silver-saw2-v4.1-l2 - qcom,sdm660-silver-saw2-v4.1-l2
- qcom,msm8998-gold-saw2-v4.1-l2 - qcom,msm8998-gold-saw2-v4.1-l2
- qcom,msm8998-silver-saw2-v4.1-l2 - qcom,msm8998-silver-saw2-v4.1-l2
- qcom,msm8916-saw2-v3.0-cpu
- qcom,msm8226-saw2-v2.1-cpu - qcom,msm8226-saw2-v2.1-cpu
- qcom,msm8974-saw2-v2.1-cpu - qcom,msm8974-saw2-v2.1-cpu
- qcom,apq8084-saw2-v2.1-cpu - qcom,apq8084-saw2-v2.1-cpu
......
# 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: ...@@ -31,6 +31,7 @@ properties:
- amlogic,meson-gxbb-sram - amlogic,meson-gxbb-sram
- arm,juno-sram-ns - arm,juno-sram-ns
- atmel,sama5d2-securam - atmel,sama5d2-securam
- qcom,rpm-msg-ram
- rockchip,rk3288-pmu-sram - rockchip,rk3288-pmu-sram
reg: reg:
...@@ -135,7 +136,9 @@ if: ...@@ -135,7 +136,9 @@ if:
properties: properties:
compatible: compatible:
contains: contains:
const: rockchip,rk3288-pmu-sram enum:
- qcom,rpm-msg-ram
- rockchip,rk3288-pmu-sram
else: else:
required: required:
......
...@@ -385,6 +385,7 @@ static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = { ...@@ -385,6 +385,7 @@ static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = {
#endif #endif
}; };
CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops); 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 = { static const struct smp_operations qcom_smp_kpssv1_ops __initconst = {
.smp_prepare_cpus = qcom_smp_prepare_cpus, .smp_prepare_cpus = qcom_smp_prepare_cpus,
......
...@@ -17,6 +17,10 @@ ...@@ -17,6 +17,10 @@
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include <linux/arm-smccc.h> #include <linux/arm-smccc.h>
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
#include <asm/smp_plat.h>
#endif
#include "qcom_scm.h" #include "qcom_scm.h"
static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT); 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, ...@@ -252,7 +256,7 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
break; break;
default: default:
pr_err("Unknown SMC convention being used\n"); pr_err("Unknown SMC convention being used\n");
return -EINVAL; return false;
} }
ret = qcom_scm_call(dev, &desc, &res); ret = qcom_scm_call(dev, &desc, &res);
...@@ -260,15 +264,44 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id, ...@@ -260,15 +264,44 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id,
return ret ? false : !!res.result[0]; return ret ? false : !!res.result[0];
} }
/** #if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
* qcom_scm_set_warm_boot_addr() - Set the warm boot address for cpus static int __qcom_scm_set_boot_addr_mc(void *entry, const cpumask_t *cpus,
* @entry: Entry point function for the cpus unsigned int flags)
* @cpus: The cpumask of cpus that will use the entry point {
* struct qcom_scm_desc desc = {
* Set the Linux entry point for the SCM to transfer control to when coming .svc = QCOM_SCM_SVC_BOOT,
* out of a power down. CPU power down may be executed on cpuidle or hotplug. .cmd = QCOM_SCM_BOOT_SET_ADDR_MC,
*/ .owner = ARM_SMCCC_OWNER_SIP,
int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) .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 ret;
int flags = 0; int flags = 0;
...@@ -304,17 +337,28 @@ int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus) ...@@ -304,17 +337,28 @@ int qcom_scm_set_warm_boot_addr(void *entry, const cpumask_t *cpus)
return ret; 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 * @entry: Entry point function for the cpus
* @cpus: The cpumask of cpus that will use the entry point * @cpus: The cpumask of cpus that will use the entry point
* *
* Set the cold boot address of the cpus. Any cpu outside the supported * Set the Linux entry point for the SCM to transfer control to when coming
* range would be removed from the cpu present mask. * 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 flags = 0;
int cpu; int cpu;
...@@ -331,9 +375,6 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) ...@@ -331,9 +375,6 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
.owner = ARM_SMCCC_OWNER_SIP, .owner = ARM_SMCCC_OWNER_SIP,
}; };
if (!cpus || cpumask_empty(cpus))
return -EINVAL;
for_each_cpu(cpu, cpus) { for_each_cpu(cpu, cpus) {
if (cpu < ARRAY_SIZE(scm_cb_flags)) if (cpu < ARRAY_SIZE(scm_cb_flags))
flags |= scm_cb_flags[cpu]; flags |= scm_cb_flags[cpu];
...@@ -346,6 +387,25 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus) ...@@ -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); 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); 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, ...@@ -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_SET_ADDR 0x01
#define QCOM_SCM_BOOT_TERMINATE_PC 0x02 #define QCOM_SCM_BOOT_TERMINATE_PC 0x02
#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10 #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_BOOT_SET_REMOTE_STATE 0x0a
#define QCOM_SCM_FLUSH_FLAG_MASK 0x3 #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_SVC_PIL 0x02
#define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01 #define QCOM_SCM_PIL_PAS_INIT_IMAGE 0x01
......
...@@ -509,6 +509,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_populate); ...@@ -509,6 +509,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_populate);
static const struct of_device_id reserved_mem_matches[] = { static const struct of_device_id reserved_mem_matches[] = {
{ .compatible = "qcom,rmtfs-mem" }, { .compatible = "qcom,rmtfs-mem" },
{ .compatible = "qcom,cmd-db" }, { .compatible = "qcom,cmd-db" },
{ .compatible = "qcom,smem" },
{ .compatible = "ramoops" }, { .compatible = "ramoops" },
{ .compatible = "nvmem-rmem" }, { .compatible = "nvmem-rmem" },
{} {}
......
...@@ -199,6 +199,16 @@ config QCOM_SPM ...@@ -199,6 +199,16 @@ config QCOM_SPM
to manage cores, L2 low power modes and to configure the internal to manage cores, L2 low power modes and to configure the internal
Adaptive Voltage Scaler parameters, where supported. 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 config QCOM_WCNSS_CTRL
tristate "Qualcomm WCNSS control driver" tristate "Qualcomm WCNSS control driver"
depends on ARCH_QCOM || COMPILE_TEST depends on ARCH_QCOM || COMPILE_TEST
......
...@@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o ...@@ -21,6 +21,7 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
obj-$(CONFIG_QCOM_SPM) += spm.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_WCNSS_CTRL) += wcnss_ctrl.o
obj-$(CONFIG_QCOM_APR) += apr.o obj-$(CONFIG_QCOM_APR) += apr.o
obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o
......
...@@ -492,12 +492,14 @@ static int of_apr_add_pd_lookups(struct device *dev) ...@@ -492,12 +492,14 @@ static int of_apr_add_pd_lookups(struct device *dev)
1, &service_path); 1, &service_path);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "pdr service path missing: %d\n", ret); dev_err(dev, "pdr service path missing: %d\n", ret);
of_node_put(node);
return ret; return ret;
} }
pds = pdr_add_lookup(apr->pdr, service_name, service_path); pds = pdr_add_lookup(apr->pdr, service_name, service_path);
if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) {
dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds)); dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds));
of_node_put(node);
return PTR_ERR(pds); return PTR_ERR(pds);
} }
} }
......
// 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 @@ ...@@ -30,6 +30,7 @@
* @active_only: True if it represents an Active only peer * @active_only: True if it represents an Active only peer
* @corner: current corner * @corner: current corner
* @active_corner: current active corner * @active_corner: current active corner
* @enable_corner: lowest non-zero corner
* @level: An array of level (vlvl) to corner (hlvl) mappings * @level: An array of level (vlvl) to corner (hlvl) mappings
* derived from cmd-db * derived from cmd-db
* @level_count: Number of levels supported by the power domain. max * @level_count: Number of levels supported by the power domain. max
...@@ -47,6 +48,7 @@ struct rpmhpd { ...@@ -47,6 +48,7 @@ struct rpmhpd {
const bool active_only; const bool active_only;
unsigned int corner; unsigned int corner;
unsigned int active_corner; unsigned int active_corner;
unsigned int enable_corner;
u32 level[RPMH_ARC_MAX_LEVELS]; u32 level[RPMH_ARC_MAX_LEVELS];
size_t level_count; size_t level_count;
bool enabled; bool enabled;
...@@ -219,7 +221,7 @@ static const struct rpmhpd_desc sm8250_desc = { ...@@ -219,7 +221,7 @@ static const struct rpmhpd_desc sm8250_desc = {
static struct rpmhpd sm8350_mxc_ao; static struct rpmhpd sm8350_mxc_ao;
static struct rpmhpd sm8350_mxc = { static struct rpmhpd sm8350_mxc = {
.pd = { .name = "mxc", }, .pd = { .name = "mxc", },
.peer = &sm8150_mmcx_ao, .peer = &sm8350_mxc_ao,
.res_name = "mxc.lvl", .res_name = "mxc.lvl",
}; };
...@@ -401,13 +403,13 @@ static int rpmhpd_aggregate_corner(struct rpmhpd *pd, unsigned int corner) ...@@ -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) static int rpmhpd_power_on(struct generic_pm_domain *domain)
{ {
struct rpmhpd *pd = domain_to_rpmhpd(domain); struct rpmhpd *pd = domain_to_rpmhpd(domain);
int ret = 0; unsigned int corner;
int ret;
mutex_lock(&rpmhpd_lock); mutex_lock(&rpmhpd_lock);
if (pd->corner) corner = max(pd->corner, pd->enable_corner);
ret = rpmhpd_aggregate_corner(pd, pd->corner); ret = rpmhpd_aggregate_corner(pd, corner);
if (!ret) if (!ret)
pd->enabled = true; pd->enabled = true;
...@@ -452,6 +454,10 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain, ...@@ -452,6 +454,10 @@ static int rpmhpd_set_performance_state(struct generic_pm_domain *domain,
i--; i--;
if (pd->enabled) { 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); ret = rpmhpd_aggregate_corner(pd, i);
if (ret) if (ret)
goto out; goto out;
...@@ -488,6 +494,10 @@ static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd) ...@@ -488,6 +494,10 @@ static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd)
for (i = 0; i < rpmhpd->level_count; i++) { for (i = 0; i < rpmhpd->level_count; i++) {
rpmhpd->level[i] = buf[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 AUX data may be zero padded. These 0 valued entries at
* the end of the map must be ignored. * the end of the map must be ignored.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/sizes.h> #include <linux/sizes.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -240,7 +241,7 @@ static const u8 SMEM_INFO_MAGIC[] = { 0x53, 0x49, 0x49, 0x49 }; /* SIII */ ...@@ -240,7 +241,7 @@ static const u8 SMEM_INFO_MAGIC[] = { 0x53, 0x49, 0x49, 0x49 }; /* SIII */
* @size: size of the memory region * @size: size of the memory region
*/ */
struct smem_region { struct smem_region {
u32 aux_base; phys_addr_t aux_base;
void __iomem *virt_base; void __iomem *virt_base;
size_t size; size_t size;
}; };
...@@ -499,7 +500,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, ...@@ -499,7 +500,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
for (i = 0; i < smem->num_regions; i++) { for (i = 0; i < smem->num_regions; i++) {
region = &smem->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) if (size != NULL)
*size = le32_to_cpu(entry->size); *size = le32_to_cpu(entry->size);
return region->virt_base + le32_to_cpu(entry->offset); return region->virt_base + le32_to_cpu(entry->offset);
...@@ -664,7 +665,7 @@ phys_addr_t qcom_smem_virt_to_phys(void *p) ...@@ -664,7 +665,7 @@ phys_addr_t qcom_smem_virt_to_phys(void *p)
if (p < region->virt_base + region->size) { if (p < region->virt_base + region->size) {
u64 offset = p - region->virt_base; 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) ...@@ -863,12 +864,12 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
return 0; return 0;
} }
static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, static int qcom_smem_resolve_mem(struct qcom_smem *smem, const char *name,
const char *name, int i) struct smem_region *region)
{ {
struct device *dev = smem->dev;
struct device_node *np; struct device_node *np;
struct resource r; struct resource r;
resource_size_t size;
int ret; int ret;
np = of_parse_phandle(dev->of_node, name, 0); 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, ...@@ -881,13 +882,9 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
of_node_put(np); of_node_put(np);
if (ret) if (ret)
return ret; return ret;
size = resource_size(&r);
smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size); region->aux_base = r.start;
if (!smem->regions[i].virt_base) region->size = resource_size(&r);
return -ENOMEM;
smem->regions[i].aux_base = (u32)r.start;
smem->regions[i].size = size;
return 0; return 0;
} }
...@@ -895,12 +892,14 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, ...@@ -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) static int qcom_smem_probe(struct platform_device *pdev)
{ {
struct smem_header *header; struct smem_header *header;
struct reserved_mem *rmem;
struct qcom_smem *smem; struct qcom_smem *smem;
size_t array_size; size_t array_size;
int num_regions; int num_regions;
int hwlock_id; int hwlock_id;
u32 version; u32 version;
int ret; int ret;
int i;
num_regions = 1; num_regions = 1;
if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL)) 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) ...@@ -914,13 +913,35 @@ static int qcom_smem_probe(struct platform_device *pdev)
smem->dev = &pdev->dev; smem->dev = &pdev->dev;
smem->num_regions = num_regions; smem->num_regions = num_regions;
ret = qcom_smem_map_memory(smem, &pdev->dev, "memory-region", 0); rmem = of_reserved_mem_lookup(pdev->dev.of_node);
if (ret) if (rmem) {
return ret; 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, if (num_regions > 1) {
"qcom,rpm-msg-ram", 1))) ret = qcom_smem_resolve_mem(smem, "qcom,rpm-msg-ram", &smem->regions[1]);
return ret; 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; header = smem->regions[0].virt_base;
if (le32_to_cpu(header->initialized) != 1 || if (le32_to_cpu(header->initialized) != 1 ||
......
...@@ -41,8 +41,11 @@ ...@@ -41,8 +41,11 @@
#define SMP2P_MAX_ENTRY_NAME 16 #define SMP2P_MAX_ENTRY_NAME 16
#define SMP2P_FEATURE_SSR_ACK 0x1 #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_MAGIC 0x504d5324
#define SMP2P_ALL_FEATURES SMP2P_FEATURE_SSR_ACK
/** /**
* struct smp2p_smem_item - in memory communication structure * struct smp2p_smem_item - in memory communication structure
...@@ -136,6 +139,10 @@ struct qcom_smp2p { ...@@ -136,6 +139,10 @@ struct qcom_smp2p {
unsigned valid_entries; unsigned valid_entries;
bool ssr_ack_enabled;
bool ssr_ack;
bool negotiation_done;
unsigned local_pid; unsigned local_pid;
unsigned remote_pid; unsigned remote_pid;
...@@ -163,22 +170,53 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p) ...@@ -163,22 +170,53 @@ static void qcom_smp2p_kick(struct qcom_smp2p *smp2p)
} }
} }
/** static bool qcom_smp2p_check_ssr(struct qcom_smp2p *smp2p)
* qcom_smp2p_intr() - interrupt handler for incoming notifications {
* @irq: unused struct smp2p_smem_item *in = smp2p->in;
* @data: smp2p driver context bool restart;
*
* Handle notifications from the remote side to handle newly allocated entries if (!smp2p->ssr_ack_enabled)
* or any changes to the state bits of existing entries. return false;
*/
static irqreturn_t qcom_smp2p_intr(int irq, void *data) 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_smem_item *in;
struct smp2p_entry *entry; 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; int irq_pin;
u32 status; u32 status;
char buf[SMP2P_MAX_ENTRY_NAME]; char buf[SMP2P_MAX_ENTRY_NAME];
...@@ -187,18 +225,6 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data) ...@@ -187,18 +225,6 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data)
in = smp2p->in; 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 */ /* Match newly created entries */
for (i = smp2p->valid_entries; i < in->valid_entries; i++) { for (i = smp2p->valid_entries; i < in->valid_entries; i++) {
list_for_each_entry(entry, &smp2p->inbound, node) { list_for_each_entry(entry, &smp2p->inbound, node) {
...@@ -237,7 +263,51 @@ static irqreturn_t qcom_smp2p_intr(int irq, void *data) ...@@ -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; return IRQ_HANDLED;
} }
...@@ -393,6 +463,7 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p) ...@@ -393,6 +463,7 @@ static int qcom_smp2p_alloc_outbound_item(struct qcom_smp2p *smp2p)
out->remote_pid = smp2p->remote_pid; out->remote_pid = smp2p->remote_pid;
out->total_entries = SMP2P_MAX_ENTRY; out->total_entries = SMP2P_MAX_ENTRY;
out->valid_entries = 0; out->valid_entries = 0;
out->features = SMP2P_ALL_FEATURES;
/* /*
* Make sure the rest of the header is written before we validate the * 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) ...@@ -502,6 +573,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL); entry = devm_kzalloc(&pdev->dev, sizeof(*entry), GFP_KERNEL);
if (!entry) { if (!entry) {
ret = -ENOMEM; ret = -ENOMEM;
of_node_put(node);
goto unwind_interfaces; goto unwind_interfaces;
} }
...@@ -509,19 +581,25 @@ static int qcom_smp2p_probe(struct platform_device *pdev) ...@@ -509,19 +581,25 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
spin_lock_init(&entry->lock); spin_lock_init(&entry->lock);
ret = of_property_read_string(node, "qcom,entry-name", &entry->name); ret = of_property_read_string(node, "qcom,entry-name", &entry->name);
if (ret < 0) if (ret < 0) {
of_node_put(node);
goto unwind_interfaces; goto unwind_interfaces;
}
if (of_property_read_bool(node, "interrupt-controller")) { if (of_property_read_bool(node, "interrupt-controller")) {
ret = qcom_smp2p_inbound_entry(smp2p, entry, node); ret = qcom_smp2p_inbound_entry(smp2p, entry, node);
if (ret < 0) if (ret < 0) {
of_node_put(node);
goto unwind_interfaces; goto unwind_interfaces;
}
list_add(&entry->node, &smp2p->inbound); list_add(&entry->node, &smp2p->inbound);
} else { } else {
ret = qcom_smp2p_outbound_entry(smp2p, entry, node); ret = qcom_smp2p_outbound_entry(smp2p, entry, node);
if (ret < 0) if (ret < 0) {
of_node_put(node);
goto unwind_interfaces; goto unwind_interfaces;
}
list_add(&entry->node, &smp2p->outbound); list_add(&entry->node, &smp2p->outbound);
} }
......
...@@ -87,8 +87,8 @@ static const char *const pmic_models[] = { ...@@ -87,8 +87,8 @@ static const char *const pmic_models[] = {
[15] = "PM8901", [15] = "PM8901",
[16] = "PM8950/PM8027", [16] = "PM8950/PM8027",
[17] = "PMI8950/ISL9519", [17] = "PMI8950/ISL9519",
[18] = "PM8921", [18] = "PMK8001/PM8921",
[19] = "PM8018", [19] = "PMI8996/PM8018",
[20] = "PM8998/PM8015", [20] = "PM8998/PM8015",
[21] = "PMI8998/PM8014", [21] = "PMI8998/PM8014",
[22] = "PM8821", [22] = "PM8821",
...@@ -102,6 +102,8 @@ static const char *const pmic_models[] = { ...@@ -102,6 +102,8 @@ static const char *const pmic_models[] = {
[32] = "PM8150B", [32] = "PM8150B",
[33] = "PMK8002", [33] = "PMK8002",
[36] = "PM8009", [36] = "PM8009",
[38] = "PM8150C",
[41] = "SMB2351",
}; };
#endif /* CONFIG_DEBUG_FS */ #endif /* CONFIG_DEBUG_FS */
......
...@@ -67,6 +67,25 @@ static const struct spm_reg_data spm_reg_8998_silver_l2 = { ...@@ -67,6 +67,25 @@ static const struct spm_reg_data spm_reg_8998_silver_l2 = {
.avs_limit = 0x4200420, .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] = { static const u16 spm_reg_offset_v2_1[SPM_REG_NR] = {
[SPM_REG_CFG] = 0x08, [SPM_REG_CFG] = 0x08,
[SPM_REG_SPM_CTL] = 0x30, [SPM_REG_SPM_CTL] = 0x30,
...@@ -176,6 +195,8 @@ static const struct of_device_id spm_match_table[] = { ...@@ -176,6 +195,8 @@ static const struct of_device_id spm_match_table[] = {
.data = &spm_reg_660_silver_l2 }, .data = &spm_reg_660_silver_l2 },
{ .compatible = "qcom,msm8226-saw2-v2.1-cpu", { .compatible = "qcom,msm8226-saw2-v2.1-cpu",
.data = &spm_reg_8226_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", { .compatible = "qcom,msm8974-saw2-v2.1-cpu",
.data = &spm_reg_8974_8084_cpu }, .data = &spm_reg_8974_8084_cpu },
{ .compatible = "qcom,msm8998-gold-saw2-v4.1-l2", { .compatible = "qcom,msm8998-gold-saw2-v4.1-l2",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment