306 lines · c
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3 * Generic OPP Interface4 *5 * Copyright (C) 2009-2010 Texas Instruments Incorporated.6 * Nishanth Menon7 * Romit Dasgupta8 * Kevin Hilman9 */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 23struct clk;24struct regulator;25 26/* Lock to allow exclusive modification to the device and opp lists */27extern struct mutex opp_table_lock;28 29extern 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#define OPP_CONFIG_REQUIRED_DEVS BIT(6)39 40/**41 * struct opp_config_data - data for set config operations42 * @opp_table: OPP table43 * @flags: OPP config flags44 *45 * This structure stores the OPP config information for each OPP table46 * configuration by the callers.47 */48struct opp_config_data {49 struct opp_table *opp_table;50 unsigned int flags;51};52 53/**54 * struct dev_pm_opp_icc_bw - Interconnect bandwidth values55 * @avg: Average bandwidth corresponding to this OPP (in icc units)56 * @peak: Peak bandwidth corresponding to this OPP (in icc units)57 *58 * This structure stores the bandwidth values for a single interconnect path.59 */60struct dev_pm_opp_icc_bw {61 u32 avg;62 u32 peak;63};64 65/*66 * Internal data structure organization with the OPP layer library is as67 * follows:68 * opp_tables (root)69 * |- device 1 (represents voltage domain 1)70 * | |- opp 1 (availability, freq, voltage)71 * | |- opp 2 ..72 * ... ...73 * | `- opp n ..74 * |- device 2 (represents the next voltage domain)75 * ...76 * `- device m (represents mth voltage domain)77 * device 1, 2.. are represented by opp_table structure while each opp78 * is represented by the opp structure.79 */80 81/**82 * struct dev_pm_opp - Generic OPP description structure83 * @node: opp table node. The nodes are maintained throughout the lifetime84 * of boot. It is expected only an optimal set of OPPs are85 * added to the library by the SoC framework.86 * IMPORTANT: the opp nodes should be maintained in increasing87 * order.88 * @kref: for reference count of the OPP.89 * @available: true/false - marks if this OPP as available or not90 * @dynamic: not-created from static DT entries.91 * @turbo: true if turbo (boost) OPP92 * @suspend: true if suspend OPP93 * @removed: flag indicating that OPP's reference is dropped by OPP core.94 * @rates: Frequencies in hertz95 * @level: Performance level96 * @supplies: Power supplies voltage/current values97 * @bandwidth: Interconnect bandwidth values98 * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's99 * frequency from any other OPP's frequency.100 * @required_opps: List of OPPs that are required by this OPP.101 * @opp_table: points back to the opp_table struct this opp belongs to102 * @np: OPP's device node.103 * @dentry: debugfs dentry pointer (per opp)104 *105 * This structure stores the OPP information for a given device.106 */107struct dev_pm_opp {108 struct list_head node;109 struct kref kref;110 111 bool available;112 bool dynamic;113 bool turbo;114 bool suspend;115 bool removed;116 unsigned long *rates;117 unsigned int level;118 119 struct dev_pm_opp_supply *supplies;120 struct dev_pm_opp_icc_bw *bandwidth;121 122 unsigned long clock_latency_ns;123 124 struct dev_pm_opp **required_opps;125 struct opp_table *opp_table;126 127 struct device_node *np;128 129#ifdef CONFIG_DEBUG_FS130 struct dentry *dentry;131 const char *of_name;132#endif133};134 135/**136 * struct opp_device - devices managed by 'struct opp_table'137 * @node: list node138 * @dev: device to which the struct object belongs139 * @dentry: debugfs dentry pointer (per device)140 *141 * This is an internal data structure maintaining the devices that are managed142 * by 'struct opp_table'.143 */144struct opp_device {145 struct list_head node;146 const struct device *dev;147 148#ifdef CONFIG_DEBUG_FS149 struct dentry *dentry;150#endif151};152 153enum opp_table_access {154 OPP_TABLE_ACCESS_UNKNOWN = 0,155 OPP_TABLE_ACCESS_EXCLUSIVE = 1,156 OPP_TABLE_ACCESS_SHARED = 2,157};158 159/**160 * struct opp_table - Device opp structure161 * @node: table node - contains the devices with OPPs that162 * have been registered. Nodes once added are not modified in this163 * table.164 * @head: notifier head to notify the OPP availability changes.165 * @dev_list: list of devices that share these OPPs166 * @opp_list: table of opps167 * @kref: for reference count of the table.168 * @lock: mutex protecting the opp_list and dev_list.169 * @np: struct device_node pointer for opp's DT node.170 * @clock_latency_ns_max: Max clock latency in nanoseconds.171 * @parsed_static_opps: Count of devices for which OPPs are initialized from DT.172 * @shared_opp: OPP is shared between multiple devices.173 * @current_rate_single_clk: Currently configured frequency for single clk.174 * @current_opp: Currently configured OPP for the table.175 * @suspend_opp: Pointer to OPP to be used during device suspend.176 * @required_opp_tables: List of device OPP tables that are required by OPPs in177 * this table.178 * @required_devs: List of devices for required OPP tables.179 * @required_opp_count: Number of required devices.180 * @supported_hw: Array of version number to support.181 * @supported_hw_count: Number of elements in supported_hw array.182 * @prop_name: A name to postfix to many DT properties, while parsing them.183 * @config_clks: Platform specific config_clks() callback.184 * @clks: Device's clock handles, for multiple clocks.185 * @clk: Device's clock handle, for single clock.186 * @clk_count: Number of clocks.187 * @config_regulators: Platform specific config_regulators() callback.188 * @regulators: Supply regulators189 * @regulator_count: Number of power supply regulators. Its value can be -1190 * (uninitialized), 0 (no opp-microvolt property) or > 0 (has opp-microvolt191 * property).192 * @paths: Interconnect path handles193 * @path_count: Number of interconnect paths194 * @enabled: Set to true if the device's resources are enabled/configured.195 * @is_genpd: Marks if the OPP table belongs to a genpd.196 * @dentry: debugfs dentry pointer of the real device directory (not links).197 * @dentry_name: Name of the real dentry.198 *199 * @voltage_tolerance_v1: In percentage, for v1 bindings only.200 *201 * This is an internal data structure maintaining the link to opps attached to202 * a device. This structure is not meant to be shared to users as it is203 * meant for book keeping and private to OPP library.204 */205struct opp_table {206 struct list_head node, lazy;207 208 struct blocking_notifier_head head;209 struct list_head dev_list;210 struct list_head opp_list;211 struct kref kref;212 struct mutex lock;213 214 struct device_node *np;215 unsigned long clock_latency_ns_max;216 217 /* For backward compatibility with v1 bindings */218 unsigned int voltage_tolerance_v1;219 220 unsigned int parsed_static_opps;221 enum opp_table_access shared_opp;222 unsigned long current_rate_single_clk;223 struct dev_pm_opp *current_opp;224 struct dev_pm_opp *suspend_opp;225 226 struct opp_table **required_opp_tables;227 struct device **required_devs;228 unsigned int required_opp_count;229 230 unsigned int *supported_hw;231 unsigned int supported_hw_count;232 const char *prop_name;233 config_clks_t config_clks;234 struct clk **clks;235 struct clk *clk;236 int clk_count;237 config_regulators_t config_regulators;238 struct regulator **regulators;239 int regulator_count;240 struct icc_path **paths;241 unsigned int path_count;242 bool enabled;243 bool is_genpd;244 245#ifdef CONFIG_DEBUG_FS246 struct dentry *dentry;247 char dentry_name[NAME_MAX];248#endif249};250 251/* Routines internal to opp core */252void dev_pm_opp_get(struct dev_pm_opp *opp);253bool _opp_remove_all_static(struct opp_table *opp_table);254void _get_opp_table_kref(struct opp_table *opp_table);255int _get_opp_count(struct opp_table *opp_table);256struct opp_table *_find_opp_table(struct device *dev);257struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table);258struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table);259void _opp_free(struct dev_pm_opp *opp);260int _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1, struct dev_pm_opp *opp2);261int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table);262int _opp_add_v1(struct opp_table *opp_table, struct device *dev, struct dev_pm_opp_data *data, bool dynamic);263void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu);264struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk);265void _put_opp_list_kref(struct opp_table *opp_table);266void _required_opps_available(struct dev_pm_opp *opp, int count);267void _update_set_required_opps(struct opp_table *opp_table);268 269static inline bool lazy_linking_pending(struct opp_table *opp_table)270{271 return unlikely(!list_empty(&opp_table->lazy));272}273 274#ifdef CONFIG_OF275void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index);276void _of_clear_opp_table(struct opp_table *opp_table);277struct opp_table *_managed_opp(struct device *dev, int index);278void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp);279#else280static inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {}281static inline void _of_clear_opp_table(struct opp_table *opp_table) {}282static inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; }283static inline void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp) {}284#endif285 286#ifdef CONFIG_DEBUG_FS287void opp_debug_remove_one(struct dev_pm_opp *opp);288void opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table);289void opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table);290void opp_debug_unregister(struct opp_device *opp_dev, struct opp_table *opp_table);291#else292static inline void opp_debug_remove_one(struct dev_pm_opp *opp) {}293 294static inline void opp_debug_create_one(struct dev_pm_opp *opp,295 struct opp_table *opp_table) { }296 297static inline void opp_debug_register(struct opp_device *opp_dev,298 struct opp_table *opp_table) { }299 300static inline void opp_debug_unregister(struct opp_device *opp_dev,301 struct opp_table *opp_table)302{ }303#endif /* DEBUG_FS */304 305#endif /* __DRIVER_OPP_H__ */306