1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * Generic OPP Interface |
4 | * |
5 | * Copyright (C) 2009-2010 Texas Instruments Incorporated. |
6 | * Nishanth Menon |
7 | * Romit Dasgupta |
8 | * Kevin Hilman |
9 | */ |
10 | |
11 | #ifndef __DRIVER_OPP_H__ |
12 | #define __DRIVER_OPP_H__ |
13 | |
14 | #include <linux/device.h> |
15 | #include <linux/interconnect.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/kref.h> |
18 | #include <linux/list.h> |
19 | #include <linux/limits.h> |
20 | #include <linux/pm_opp.h> |
21 | #include <linux/notifier.h> |
22 | |
23 | struct clk; |
24 | struct regulator; |
25 | |
26 | /* Lock to allow exclusive modification to the device and opp lists */ |
27 | extern struct mutex opp_table_lock; |
28 | |
29 | extern struct list_head opp_tables; |
30 | |
31 | /* OPP Config flags */ |
32 | #define OPP_CONFIG_CLK BIT(0) |
33 | #define OPP_CONFIG_REGULATOR BIT(1) |
34 | #define OPP_CONFIG_REGULATOR_HELPER BIT(2) |
35 | #define OPP_CONFIG_PROP_NAME BIT(3) |
36 | #define OPP_CONFIG_SUPPORTED_HW BIT(4) |
37 | #define OPP_CONFIG_GENPD BIT(5) |
38 | |
39 | /** |
40 | * struct opp_config_data - data for set config operations |
41 | * @opp_table: OPP table |
42 | * @flags: OPP config flags |
43 | * |
44 | * This structure stores the OPP config information for each OPP table |
45 | * configuration by the callers. |
46 | */ |
47 | struct opp_config_data { |
48 | struct opp_table *opp_table; |
49 | unsigned int flags; |
50 | }; |
51 | |
52 | /* |
53 | * Internal data structure organization with the OPP layer library is as |
54 | * follows: |
55 | * opp_tables (root) |
56 | * |- device 1 (represents voltage domain 1) |
57 | * | |- opp 1 (availability, freq, voltage) |
58 | * | |- opp 2 .. |
59 | * ... ... |
60 | * | `- opp n .. |
61 | * |- device 2 (represents the next voltage domain) |
62 | * ... |
63 | * `- device m (represents mth voltage domain) |
64 | * device 1, 2.. are represented by opp_table structure while each opp |
65 | * is represented by the opp structure. |
66 | */ |
67 | |
68 | /** |
69 | * struct dev_pm_opp - Generic OPP description structure |
70 | * @node: opp table node. The nodes are maintained throughout the lifetime |
71 | * of boot. It is expected only an optimal set of OPPs are |
72 | * added to the library by the SoC framework. |
73 | * IMPORTANT: the opp nodes should be maintained in increasing |
74 | * order. |
75 | * @kref: for reference count of the OPP. |
76 | * @available: true/false - marks if this OPP as available or not |
77 | * @dynamic: not-created from static DT entries. |
78 | * @turbo: true if turbo (boost) OPP |
79 | * @suspend: true if suspend OPP |
80 | * @removed: flag indicating that OPP's reference is dropped by OPP core. |
81 | * @rates: Frequencies in hertz |
82 | * @level: Performance level |
83 | * @supplies: Power supplies voltage/current values |
84 | * @bandwidth: Interconnect bandwidth values |
85 | * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's |
86 | * frequency from any other OPP's frequency. |
87 | * @required_opps: List of OPPs that are required by this OPP. |
88 | * @opp_table: points back to the opp_table struct this opp belongs to |
89 | * @np: OPP's device node. |
90 | * @dentry: debugfs dentry pointer (per opp) |
91 | * |
92 | * This structure stores the OPP information for a given device. |
93 | */ |
94 | struct dev_pm_opp { |
95 | struct list_head node; |
96 | struct kref kref; |
97 | |
98 | bool available; |
99 | bool dynamic; |
100 | bool turbo; |
101 | bool suspend; |
102 | bool removed; |
103 | unsigned long *rates; |
104 | unsigned int level; |
105 | |
106 | struct dev_pm_opp_supply *supplies; |
107 | struct dev_pm_opp_icc_bw *bandwidth; |
108 | |
109 | unsigned long clock_latency_ns; |
110 | |
111 | struct dev_pm_opp **required_opps; |
112 | struct opp_table *opp_table; |
113 | |
114 | struct device_node *np; |
115 | |
116 | #ifdef CONFIG_DEBUG_FS |
117 | struct dentry *dentry; |
118 | const char *of_name; |
119 | #endif |
120 | }; |
121 | |
122 | /** |
123 | * struct opp_device - devices managed by 'struct opp_table' |
124 | * @node: list node |
125 | * @dev: device to which the struct object belongs |
126 | * @dentry: debugfs dentry pointer (per device) |
127 | * |
128 | * This is an internal data structure maintaining the devices that are managed |
129 | * by 'struct opp_table'. |
130 | */ |
131 | struct opp_device { |
132 | struct list_head node; |
133 | const struct device *dev; |
134 | |
135 | #ifdef CONFIG_DEBUG_FS |
136 | struct dentry *dentry; |
137 | #endif |
138 | }; |
139 | |
140 | enum opp_table_access { |
141 | OPP_TABLE_ACCESS_UNKNOWN = 0, |
142 | OPP_TABLE_ACCESS_EXCLUSIVE = 1, |
143 | OPP_TABLE_ACCESS_SHARED = 2, |
144 | }; |
145 | |
146 | /** |
147 | * struct opp_table - Device opp structure |
148 | * @node: table node - contains the devices with OPPs that |
149 | * have been registered. Nodes once added are not modified in this |
150 | * table. |
151 | * @head: notifier head to notify the OPP availability changes. |
152 | * @dev_list: list of devices that share these OPPs |
153 | * @opp_list: table of opps |
154 | * @kref: for reference count of the table. |
155 | * @lock: mutex protecting the opp_list and dev_list. |
156 | * @np: struct device_node pointer for opp's DT node. |
157 | * @clock_latency_ns_max: Max clock latency in nanoseconds. |
158 | * @parsed_static_opps: Count of devices for which OPPs are initialized from DT. |
159 | * @shared_opp: OPP is shared between multiple devices. |
160 | * @rate_clk_single: Currently configured frequency for single clk. |
161 | * @current_opp: Currently configured OPP for the table. |
162 | * @suspend_opp: Pointer to OPP to be used during device suspend. |
163 | * @genpd_virt_devs: List of virtual devices for multiple genpd support. |
164 | * @required_opp_tables: List of device OPP tables that are required by OPPs in |
165 | * this table. |
166 | * @required_opp_count: Number of required devices. |
167 | * @supported_hw: Array of version number to support. |
168 | * @supported_hw_count: Number of elements in supported_hw array. |
169 | * @prop_name: A name to postfix to many DT properties, while parsing them. |
170 | * @config_clks: Platform specific config_clks() callback. |
171 | * @clks: Device's clock handles, for multiple clocks. |
172 | * @clk: Device's clock handle, for single clock. |
173 | * @clk_count: Number of clocks. |
174 | * @config_regulators: Platform specific config_regulators() callback. |
175 | * @regulators: Supply regulators |
176 | * @regulator_count: Number of power supply regulators. Its value can be -1 |
177 | * (uninitialized), 0 (no opp-microvolt property) or > 0 (has opp-microvolt |
178 | * property). |
179 | * @paths: Interconnect path handles |
180 | * @path_count: Number of interconnect paths |
181 | * @enabled: Set to true if the device's resources are enabled/configured. |
182 | * @is_genpd: Marks if the OPP table belongs to a genpd. |
183 | * @set_required_opps: Helper responsible to set required OPPs. |
184 | * @dentry: debugfs dentry pointer of the real device directory (not links). |
185 | * @dentry_name: Name of the real dentry. |
186 | * |
187 | * @voltage_tolerance_v1: In percentage, for v1 bindings only. |
188 | * |
189 | * This is an internal data structure maintaining the link to opps attached to |
190 | * a device. This structure is not meant to be shared to users as it is |
191 | * meant for book keeping and private to OPP library. |
192 | */ |
193 | struct opp_table { |
194 | struct list_head node, lazy; |
195 | |
196 | struct blocking_notifier_head head; |
197 | struct list_head dev_list; |
198 | struct list_head opp_list; |
199 | struct kref kref; |
200 | struct mutex lock; |
201 | |
202 | struct device_node *np; |
203 | unsigned long clock_latency_ns_max; |
204 | |
205 | /* For backward compatibility with v1 bindings */ |
206 | unsigned int voltage_tolerance_v1; |
207 | |
208 | unsigned int parsed_static_opps; |
209 | enum opp_table_access shared_opp; |
210 | unsigned long rate_clk_single; |
211 | struct dev_pm_opp *current_opp; |
212 | struct dev_pm_opp *suspend_opp; |
213 | |
214 | struct device **genpd_virt_devs; |
215 | struct opp_table **required_opp_tables; |
216 | unsigned int required_opp_count; |
217 | |
218 | unsigned int *supported_hw; |
219 | unsigned int supported_hw_count; |
220 | const char *prop_name; |
221 | config_clks_t config_clks; |
222 | struct clk **clks; |
223 | struct clk *clk; |
224 | int clk_count; |
225 | config_regulators_t config_regulators; |
226 | struct regulator **regulators; |
227 | int regulator_count; |
228 | struct icc_path **paths; |
229 | unsigned int path_count; |
230 | bool enabled; |
231 | bool is_genpd; |
232 | int (*set_required_opps)(struct device *dev, |
233 | struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down); |
234 | |
235 | #ifdef CONFIG_DEBUG_FS |
236 | struct dentry *dentry; |
237 | char dentry_name[NAME_MAX]; |
238 | #endif |
239 | }; |
240 | |
241 | /* Routines internal to opp core */ |
242 | void dev_pm_opp_get(struct dev_pm_opp *opp); |
243 | bool _opp_remove_all_static(struct opp_table *opp_table); |
244 | void _get_opp_table_kref(struct opp_table *opp_table); |
245 | int _get_opp_count(struct opp_table *opp_table); |
246 | struct opp_table *_find_opp_table(struct device *dev); |
247 | struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); |
248 | struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); |
249 | void _opp_free(struct dev_pm_opp *opp); |
250 | int _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1, struct dev_pm_opp *opp2); |
251 | int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table); |
252 | int _opp_add_v1(struct opp_table *opp_table, struct device *dev, struct dev_pm_opp_data *data, bool dynamic); |
253 | void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu); |
254 | struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk); |
255 | void _put_opp_list_kref(struct opp_table *opp_table); |
256 | void _required_opps_available(struct dev_pm_opp *opp, int count); |
257 | void _update_set_required_opps(struct opp_table *opp_table); |
258 | |
259 | static inline bool lazy_linking_pending(struct opp_table *opp_table) |
260 | { |
261 | return unlikely(!list_empty(&opp_table->lazy)); |
262 | } |
263 | |
264 | #ifdef CONFIG_OF |
265 | void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index); |
266 | void _of_clear_opp_table(struct opp_table *opp_table); |
267 | struct opp_table *_managed_opp(struct device *dev, int index); |
268 | void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp); |
269 | #else |
270 | static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {} |
271 | static inline void _of_clear_opp_table(struct opp_table *opp_table) {} |
272 | static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; } |
273 | static inline void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp) {} |
274 | #endif |
275 | |
276 | #ifdef CONFIG_DEBUG_FS |
277 | void opp_debug_remove_one(struct dev_pm_opp *opp); |
278 | void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table); |
279 | void opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table); |
280 | void opp_debug_unregister(struct opp_device *opp_dev, struct opp_table *opp_table); |
281 | #else |
282 | static inline void opp_debug_remove_one(struct dev_pm_opp *opp) {} |
283 | |
284 | static inline void opp_debug_create_one(struct dev_pm_opp *opp, |
285 | struct opp_table *opp_table) { } |
286 | |
287 | static inline void opp_debug_register(struct opp_device *opp_dev, |
288 | struct opp_table *opp_table) { } |
289 | |
290 | static inline void opp_debug_unregister(struct opp_device *opp_dev, |
291 | struct opp_table *opp_table) |
292 | { } |
293 | #endif /* DEBUG_FS */ |
294 | |
295 | #endif /* __DRIVER_OPP_H__ */ |
296 | |