Raghavendra Kakarla | fbcacdf | 2018-03-09 18:27:33 +0530 | [diff] [blame] | 1 | /* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 2 | * |
| 3 | * This program is free software; you can redistribute it and/or modify |
| 4 | * it under the terms of the GNU General Public License version 2 and |
| 5 | * only version 2 as published by the Free Software Foundation. |
| 6 | * |
| 7 | * This program is distributed in the hope that it will be useful, |
| 8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 10 | * GNU General Public License for more details. |
| 11 | */ |
| 12 | |
| 13 | #include <soc/qcom/pm.h> |
| 14 | #include <soc/qcom/spm.h> |
| 15 | |
| 16 | #define NR_LPM_LEVELS 8 |
| 17 | #define MAXSAMPLES 5 |
| 18 | #define CLUST_SMPL_INVLD_TIME 40000 |
Raghavendra Kakarla | fbcacdf | 2018-03-09 18:27:33 +0530 | [diff] [blame] | 19 | #define DEFAULT_PREMATURE_CNT 3 |
| 20 | #define DEFAULT_STDDEV 100 |
| 21 | #define DEFAULT_TIMER_ADD 100 |
| 22 | #define TIMER_ADD_LOW 100 |
| 23 | #define TIMER_ADD_HIGH 1500 |
| 24 | #define STDDEV_LOW 100 |
| 25 | #define STDDEV_HIGH 1000 |
| 26 | #define PREMATURE_CNT_LOW 1 |
| 27 | #define PREMATURE_CNT_HIGH 5 |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 28 | |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 29 | struct power_params { |
| 30 | uint32_t latency_us; /* Enter + Exit latency */ |
| 31 | uint32_t ss_power; /* Steady state power */ |
| 32 | uint32_t energy_overhead; /* Enter + exit over head */ |
| 33 | uint32_t time_overhead_us; /* Enter + exit overhead */ |
| 34 | uint32_t residencies[NR_LPM_LEVELS]; |
| 35 | uint32_t min_residency; |
| 36 | uint32_t max_residency; |
| 37 | }; |
| 38 | |
| 39 | struct lpm_cpu_level { |
| 40 | const char *name; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 41 | bool use_bc_timer; |
| 42 | struct power_params pwr; |
| 43 | unsigned int psci_id; |
| 44 | bool is_reset; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 45 | int reset_level; |
| 46 | }; |
| 47 | |
| 48 | struct lpm_cpu { |
Mahesh Sivasubramanian | 168922d | 2017-06-09 09:47:52 -0600 | [diff] [blame] | 49 | struct list_head list; |
| 50 | struct cpumask related_cpus; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 51 | struct lpm_cpu_level levels[NR_LPM_LEVELS]; |
| 52 | int nlevels; |
| 53 | unsigned int psci_mode_shift; |
| 54 | unsigned int psci_mode_mask; |
Raghavendra Kakarla | fbcacdf | 2018-03-09 18:27:33 +0530 | [diff] [blame] | 55 | uint32_t ref_stddev; |
| 56 | uint32_t ref_premature_cnt; |
| 57 | uint32_t tmr_add; |
Mahesh Sivasubramanian | 7381092 | 2017-10-16 16:46:56 -0600 | [diff] [blame] | 58 | bool lpm_prediction; |
Mahesh Sivasubramanian | 168922d | 2017-06-09 09:47:52 -0600 | [diff] [blame] | 59 | struct cpuidle_driver *drv; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 60 | struct lpm_cluster *parent; |
| 61 | }; |
| 62 | |
| 63 | struct lpm_level_avail { |
| 64 | bool idle_enabled; |
| 65 | bool suspend_enabled; |
Mahesh Sivasubramanian | 62b3a6b | 2017-05-19 15:33:11 -0600 | [diff] [blame] | 66 | uint32_t latency_us; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 67 | struct kobject *kobj; |
| 68 | struct kobj_attribute idle_enabled_attr; |
| 69 | struct kobj_attribute suspend_enabled_attr; |
Mahesh Sivasubramanian | 62b3a6b | 2017-05-19 15:33:11 -0600 | [diff] [blame] | 70 | struct kobj_attribute latency_attr; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 71 | void *data; |
| 72 | int idx; |
| 73 | bool cpu_node; |
| 74 | }; |
| 75 | |
| 76 | struct lpm_cluster_level { |
| 77 | const char *level_name; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 78 | int min_child_level; |
| 79 | struct cpumask num_cpu_votes; |
| 80 | struct power_params pwr; |
| 81 | bool notify_rpm; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 82 | bool sync_level; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 83 | struct lpm_level_avail available; |
| 84 | unsigned int psci_id; |
| 85 | bool is_reset; |
| 86 | int reset_level; |
| 87 | }; |
| 88 | |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 89 | struct cluster_history { |
| 90 | uint32_t resi[MAXSAMPLES]; |
| 91 | int mode[MAXSAMPLES]; |
| 92 | int64_t stime[MAXSAMPLES]; |
| 93 | uint32_t hptr; |
| 94 | uint32_t hinvalid; |
| 95 | uint32_t htmr_wkup; |
| 96 | uint64_t entry_time; |
| 97 | int entry_idx; |
| 98 | int nsamp; |
| 99 | int flag; |
| 100 | }; |
| 101 | |
| 102 | struct lpm_cluster { |
| 103 | struct list_head list; |
| 104 | struct list_head child; |
| 105 | const char *cluster_name; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 106 | unsigned long aff_level; /* Affinity level of the node */ |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 107 | struct lpm_cluster_level levels[NR_LPM_LEVELS]; |
| 108 | int nlevels; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 109 | int min_child_level; |
| 110 | int default_level; |
| 111 | int last_level; |
Raghavendra Kakarla | fbcacdf | 2018-03-09 18:27:33 +0530 | [diff] [blame] | 112 | uint32_t tmr_add; |
| 113 | bool lpm_prediction; |
Mahesh Sivasubramanian | 168922d | 2017-06-09 09:47:52 -0600 | [diff] [blame] | 114 | struct list_head cpu; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 115 | spinlock_t sync_lock; |
| 116 | struct cpumask child_cpus; |
| 117 | struct cpumask num_children_in_sync; |
| 118 | struct lpm_cluster *parent; |
| 119 | struct lpm_stats *stats; |
| 120 | unsigned int psci_mode_shift; |
| 121 | unsigned int psci_mode_mask; |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 122 | struct cluster_history history; |
| 123 | struct hrtimer histtimer; |
| 124 | }; |
| 125 | |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 126 | struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev); |
| 127 | void free_cluster_node(struct lpm_cluster *cluster); |
| 128 | void cluster_dt_walkthrough(struct lpm_cluster *cluster); |
| 129 | |
| 130 | int create_cluster_lvl_nodes(struct lpm_cluster *p, struct kobject *kobj); |
| 131 | bool lpm_cpu_mode_allow(unsigned int cpu, |
| 132 | unsigned int mode, bool from_idle); |
| 133 | bool lpm_cluster_mode_allow(struct lpm_cluster *cluster, |
| 134 | unsigned int mode, bool from_idle); |
| 135 | uint32_t *get_per_cpu_max_residency(int cpu); |
| 136 | uint32_t *get_per_cpu_min_residency(int cpu); |
| 137 | extern struct lpm_cluster *lpm_root_node; |
| 138 | |
Lina Iyer | 461ad8f | 2017-11-09 00:57:38 +0000 | [diff] [blame] | 139 | #if defined(CONFIG_SMP) |
Mahesh Sivasubramanian | c2ea76f | 2016-02-01 10:40:26 -0700 | [diff] [blame] | 140 | extern DEFINE_PER_CPU(bool, pending_ipi); |
| 141 | static inline bool is_IPI_pending(const struct cpumask *mask) |
| 142 | { |
| 143 | unsigned int cpu; |
| 144 | |
| 145 | for_each_cpu(cpu, mask) { |
| 146 | if per_cpu(pending_ipi, cpu) |
| 147 | return true; |
| 148 | } |
| 149 | return false; |
| 150 | } |
| 151 | #else |
| 152 | static inline bool is_IPI_pending(const struct cpumask *mask) |
| 153 | { |
| 154 | return false; |
| 155 | } |
| 156 | #endif |