Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0560d0e5 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "cpuidle: lpm-levels: Enable LPM support for non psci target"

parents 02ead738 b9ad4526
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
* LPM Workarounds

The required properties are:

- compatible: "qcom,lpm-workarounds"

The optional properties are:
- reg: The physical address and the size of the l1_l2_gcc and l2_pwr_sts
	regitsters of performance cluster.

- reg-names: "l2_pwr_sts" - string to identify l2_pwr_sts physical address.
	     "l1_l2_gcc" - string to identify l1_l2_gcc physical address.

- qcom,lpm-wa-cx-turbo-unvote: Indicates the workaround to unvote CX turbo
	vote when system is coming out of rpm assisted power collaspe.
	lpm-cx-supply is required if this is present.

- lpm-cx-supply:  will hold handle for CX regulator supply which is used
	to unvote.

- qcom,lpm-wa-skip-l2-spm: Due to a hardware bug on 8939 and 8909, secure
	world needs to disable and enable L2 SPM to get the proper context
	in secure watchdog bite cases. With this workaround there is a race
	in programming L2 SPM between HLOS and secure world. This leads to
	stability issues. To avoid this program L2 SPM only in secure world
	based on the L2 mode flag passed. Set lpm-wa-skip-l2-spm node if this
	is required.

- qcom,lpm-wa-dynamic-clock-gating: Due to a hardware bug on 8952, L1/L2 dynamic
	clock gating needs to be enabled by software for performance cluster
	cores and L2. Set lpm-wa-dynamic-clock-gating node if this workaround is
	required.

- qcom,cpu-offline-mask: Dynamic clock gating should be enabled when cluster is
	in L2 PC. Each bit of cpu-offline-mask lists the cpu no. to hotplug by KTM
	driver.

- qcom,non-boot-cpu-index: will hold index of non boot cluster cpu.

- qcom,l1-l2-gcc-secure: indicates L1/L2 clock enabling register is secure.

Example:

qcom,lpm-workarounds {
	compatible = "qcom,lpm-workarounds";
	reg = <0x0B011018 0x4>,
	      <0x0B011088 0x4>;
	reg-names = "l2-pwr-sts", "l1-l2-gcc";
	lpm-cx-supply = <&pm8916_s2_corner>;
	qcom,lpm-wa-cx-turbo-unvote;
	qcom,lpm-wa-skip-l2-spm;
	qcom,lpm-wa-dynamic-clock-gating;
	qcom,cpu-offline-mask = "0xF";
	qcom,non-boot-cpu-index = <4>;
}
+4 −0
Original line number Diff line number Diff line
@@ -27,4 +27,8 @@ obj-$(CONFIG_MIPS_CPS_CPUIDLE) += cpuidle-cps.o
# POWERPC drivers
obj-$(CONFIG_PSERIES_CPUIDLE)		+= cpuidle-pseries.o
obj-$(CONFIG_POWERNV_CPUIDLE)		+= cpuidle-powernv.o
ifeq ($(CONFIG_MSM_PM_LEGACY), y)
obj-y += lpm-levels-legacy.o lpm-levels-of-legacy.o lpm-workarounds.o
else
obj-$(CONFIG_MSM_PM) += lpm-levels.o lpm-levels-of.o
endif
+1523 −0

File added.

Preview size limit exceeded, changes collapsed.

+152 −0
Original line number Diff line number Diff line
/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <soc/qcom/pm-legacy.h>
#include <soc/qcom/spm.h>

#define NR_LPM_LEVELS 8

extern bool use_psci;

struct lpm_lookup_table {
	uint32_t modes;
	const char *mode_name;
};

struct power_params {
	uint32_t latency_us;		/* Enter + Exit latency */
	uint32_t ss_power;		/* Steady state power */
	uint32_t energy_overhead;	/* Enter + exit over head */
	uint32_t time_overhead_us;	/* Enter + exit overhead */
	uint32_t residencies[NR_LPM_LEVELS];
	uint32_t max_residency;
};

struct lpm_cpu_level {
	const char *name;
	enum msm_pm_sleep_mode mode;
	bool use_bc_timer;
	struct power_params pwr;
	unsigned int psci_id;
	bool is_reset;
	bool jtag_save_restore;
	bool hyp_psci;
	int reset_level;
};

struct lpm_cpu {
	struct lpm_cpu_level levels[NR_LPM_LEVELS];
	int nlevels;
	unsigned int psci_mode_shift;
	unsigned int psci_mode_mask;
	struct lpm_cluster *parent;
};

struct lpm_level_avail {
	bool idle_enabled;
	bool suspend_enabled;
	struct kobject *kobj;
	struct kobj_attribute idle_enabled_attr;
	struct kobj_attribute suspend_enabled_attr;
	void *data;
	int idx;
	bool cpu_node;
};

struct lpm_cluster_level {
	const char *level_name;
	int *mode;			/* SPM mode to enter */
	int min_child_level;
	struct cpumask num_cpu_votes;
	struct power_params pwr;
	bool notify_rpm;
	bool disable_dynamic_routing;
	bool sync_level;
	bool last_core_only;
	struct lpm_level_avail available;
	unsigned int psci_id;
	bool is_reset;
	int reset_level;
	bool no_cache_flush;
};

struct low_power_ops {
	struct msm_spm_device *spm;
	int (*set_mode)(struct low_power_ops *ops, int mode,
				struct lpm_cluster_level *level);
	enum msm_pm_l2_scm_flag tz_flag;
};

struct lpm_cluster {
	struct list_head list;
	struct list_head child;
	const char *cluster_name;
	const char **name;
	unsigned long aff_level; /* Affinity level of the node */
	struct low_power_ops *lpm_dev;
	int ndevices;
	struct lpm_cluster_level levels[NR_LPM_LEVELS];
	int nlevels;
	enum msm_pm_l2_scm_flag l2_flag;
	int min_child_level;
	int default_level;
	int last_level;
	struct lpm_cpu *cpu;
	struct cpuidle_driver *drv;
	spinlock_t sync_lock;
	struct cpumask child_cpus;
	struct cpumask num_children_in_sync;
	struct lpm_cluster *parent;
	struct lpm_stats *stats;
	unsigned int psci_mode_shift;
	unsigned int psci_mode_mask;
	bool no_saw_devices;
};

int set_l2_mode(struct low_power_ops *ops, int mode,
				struct lpm_cluster_level *level);
int set_system_mode(struct low_power_ops *ops, int mode,
				struct lpm_cluster_level *level);
int set_l3_mode(struct low_power_ops *ops, int mode,
				struct lpm_cluster_level *level);
void lpm_suspend_wake_time(uint64_t wakeup_time);

struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev);
void free_cluster_node(struct lpm_cluster *cluster);
void cluster_dt_walkthrough(struct lpm_cluster *cluster);

int create_cluster_lvl_nodes(struct lpm_cluster *p, struct kobject *kobj);
bool lpm_cpu_mode_allow(unsigned int cpu,
		unsigned int mode, bool from_idle);
bool lpm_cluster_mode_allow(struct lpm_cluster *cluster,
		unsigned int mode, bool from_idle);
uint32_t *get_per_cpu_max_residency(int cpu);
extern struct lpm_cluster *lpm_root_node;

#ifdef CONFIG_SMP
extern DEFINE_PER_CPU(bool, pending_ipi);
static inline bool is_IPI_pending(const struct cpumask *mask)
{
	unsigned int cpu;

	for_each_cpu(cpu, mask) {
		if per_cpu(pending_ipi, cpu)
			return true;
	}
	return false;
}
#else
static inline bool is_IPI_pending(const struct cpumask *mask)
{
	return false;
}
#endif
+1006 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading