162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Generic OPP Interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2009-2010 Texas Instruments Incorporated. 662306a36Sopenharmony_ci * Nishanth Menon 762306a36Sopenharmony_ci * Romit Dasgupta 862306a36Sopenharmony_ci * Kevin Hilman 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#ifndef __DRIVER_OPP_H__ 1262306a36Sopenharmony_ci#define __DRIVER_OPP_H__ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/interconnect.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/kref.h> 1862306a36Sopenharmony_ci#include <linux/list.h> 1962306a36Sopenharmony_ci#include <linux/limits.h> 2062306a36Sopenharmony_ci#include <linux/pm_opp.h> 2162306a36Sopenharmony_ci#include <linux/notifier.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct clk; 2462306a36Sopenharmony_cistruct regulator; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* Lock to allow exclusive modification to the device and opp lists */ 2762306a36Sopenharmony_ciextern struct mutex opp_table_lock; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciextern struct list_head opp_tables; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* OPP Config flags */ 3262306a36Sopenharmony_ci#define OPP_CONFIG_CLK BIT(0) 3362306a36Sopenharmony_ci#define OPP_CONFIG_REGULATOR BIT(1) 3462306a36Sopenharmony_ci#define OPP_CONFIG_REGULATOR_HELPER BIT(2) 3562306a36Sopenharmony_ci#define OPP_CONFIG_PROP_NAME BIT(3) 3662306a36Sopenharmony_ci#define OPP_CONFIG_SUPPORTED_HW BIT(4) 3762306a36Sopenharmony_ci#define OPP_CONFIG_GENPD BIT(5) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/** 4062306a36Sopenharmony_ci * struct opp_config_data - data for set config operations 4162306a36Sopenharmony_ci * @opp_table: OPP table 4262306a36Sopenharmony_ci * @flags: OPP config flags 4362306a36Sopenharmony_ci * 4462306a36Sopenharmony_ci * This structure stores the OPP config information for each OPP table 4562306a36Sopenharmony_ci * configuration by the callers. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cistruct opp_config_data { 4862306a36Sopenharmony_ci struct opp_table *opp_table; 4962306a36Sopenharmony_ci unsigned int flags; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * Internal data structure organization with the OPP layer library is as 5462306a36Sopenharmony_ci * follows: 5562306a36Sopenharmony_ci * opp_tables (root) 5662306a36Sopenharmony_ci * |- device 1 (represents voltage domain 1) 5762306a36Sopenharmony_ci * | |- opp 1 (availability, freq, voltage) 5862306a36Sopenharmony_ci * | |- opp 2 .. 5962306a36Sopenharmony_ci * ... ... 6062306a36Sopenharmony_ci * | `- opp n .. 6162306a36Sopenharmony_ci * |- device 2 (represents the next voltage domain) 6262306a36Sopenharmony_ci * ... 6362306a36Sopenharmony_ci * `- device m (represents mth voltage domain) 6462306a36Sopenharmony_ci * device 1, 2.. are represented by opp_table structure while each opp 6562306a36Sopenharmony_ci * is represented by the opp structure. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/** 6962306a36Sopenharmony_ci * struct dev_pm_opp - Generic OPP description structure 7062306a36Sopenharmony_ci * @node: opp table node. The nodes are maintained throughout the lifetime 7162306a36Sopenharmony_ci * of boot. It is expected only an optimal set of OPPs are 7262306a36Sopenharmony_ci * added to the library by the SoC framework. 7362306a36Sopenharmony_ci * IMPORTANT: the opp nodes should be maintained in increasing 7462306a36Sopenharmony_ci * order. 7562306a36Sopenharmony_ci * @kref: for reference count of the OPP. 7662306a36Sopenharmony_ci * @available: true/false - marks if this OPP as available or not 7762306a36Sopenharmony_ci * @dynamic: not-created from static DT entries. 7862306a36Sopenharmony_ci * @turbo: true if turbo (boost) OPP 7962306a36Sopenharmony_ci * @suspend: true if suspend OPP 8062306a36Sopenharmony_ci * @removed: flag indicating that OPP's reference is dropped by OPP core. 8162306a36Sopenharmony_ci * @rates: Frequencies in hertz 8262306a36Sopenharmony_ci * @level: Performance level 8362306a36Sopenharmony_ci * @supplies: Power supplies voltage/current values 8462306a36Sopenharmony_ci * @bandwidth: Interconnect bandwidth values 8562306a36Sopenharmony_ci * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's 8662306a36Sopenharmony_ci * frequency from any other OPP's frequency. 8762306a36Sopenharmony_ci * @required_opps: List of OPPs that are required by this OPP. 8862306a36Sopenharmony_ci * @opp_table: points back to the opp_table struct this opp belongs to 8962306a36Sopenharmony_ci * @np: OPP's device node. 9062306a36Sopenharmony_ci * @dentry: debugfs dentry pointer (per opp) 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * This structure stores the OPP information for a given device. 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistruct dev_pm_opp { 9562306a36Sopenharmony_ci struct list_head node; 9662306a36Sopenharmony_ci struct kref kref; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci bool available; 9962306a36Sopenharmony_ci bool dynamic; 10062306a36Sopenharmony_ci bool turbo; 10162306a36Sopenharmony_ci bool suspend; 10262306a36Sopenharmony_ci bool removed; 10362306a36Sopenharmony_ci unsigned long *rates; 10462306a36Sopenharmony_ci unsigned int level; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci struct dev_pm_opp_supply *supplies; 10762306a36Sopenharmony_ci struct dev_pm_opp_icc_bw *bandwidth; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci unsigned long clock_latency_ns; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci struct dev_pm_opp **required_opps; 11262306a36Sopenharmony_ci struct opp_table *opp_table; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci struct device_node *np; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 11762306a36Sopenharmony_ci struct dentry *dentry; 11862306a36Sopenharmony_ci const char *of_name; 11962306a36Sopenharmony_ci#endif 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/** 12362306a36Sopenharmony_ci * struct opp_device - devices managed by 'struct opp_table' 12462306a36Sopenharmony_ci * @node: list node 12562306a36Sopenharmony_ci * @dev: device to which the struct object belongs 12662306a36Sopenharmony_ci * @dentry: debugfs dentry pointer (per device) 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * This is an internal data structure maintaining the devices that are managed 12962306a36Sopenharmony_ci * by 'struct opp_table'. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_cistruct opp_device { 13262306a36Sopenharmony_ci struct list_head node; 13362306a36Sopenharmony_ci const struct device *dev; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 13662306a36Sopenharmony_ci struct dentry *dentry; 13762306a36Sopenharmony_ci#endif 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cienum opp_table_access { 14162306a36Sopenharmony_ci OPP_TABLE_ACCESS_UNKNOWN = 0, 14262306a36Sopenharmony_ci OPP_TABLE_ACCESS_EXCLUSIVE = 1, 14362306a36Sopenharmony_ci OPP_TABLE_ACCESS_SHARED = 2, 14462306a36Sopenharmony_ci}; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/** 14762306a36Sopenharmony_ci * struct opp_table - Device opp structure 14862306a36Sopenharmony_ci * @node: table node - contains the devices with OPPs that 14962306a36Sopenharmony_ci * have been registered. Nodes once added are not modified in this 15062306a36Sopenharmony_ci * table. 15162306a36Sopenharmony_ci * @head: notifier head to notify the OPP availability changes. 15262306a36Sopenharmony_ci * @dev_list: list of devices that share these OPPs 15362306a36Sopenharmony_ci * @opp_list: table of opps 15462306a36Sopenharmony_ci * @kref: for reference count of the table. 15562306a36Sopenharmony_ci * @lock: mutex protecting the opp_list and dev_list. 15662306a36Sopenharmony_ci * @np: struct device_node pointer for opp's DT node. 15762306a36Sopenharmony_ci * @clock_latency_ns_max: Max clock latency in nanoseconds. 15862306a36Sopenharmony_ci * @parsed_static_opps: Count of devices for which OPPs are initialized from DT. 15962306a36Sopenharmony_ci * @shared_opp: OPP is shared between multiple devices. 16062306a36Sopenharmony_ci * @rate_clk_single: Currently configured frequency for single clk. 16162306a36Sopenharmony_ci * @current_opp: Currently configured OPP for the table. 16262306a36Sopenharmony_ci * @suspend_opp: Pointer to OPP to be used during device suspend. 16362306a36Sopenharmony_ci * @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers. 16462306a36Sopenharmony_ci * @genpd_virt_devs: List of virtual devices for multiple genpd support. 16562306a36Sopenharmony_ci * @required_opp_tables: List of device OPP tables that are required by OPPs in 16662306a36Sopenharmony_ci * this table. 16762306a36Sopenharmony_ci * @required_opp_count: Number of required devices. 16862306a36Sopenharmony_ci * @supported_hw: Array of version number to support. 16962306a36Sopenharmony_ci * @supported_hw_count: Number of elements in supported_hw array. 17062306a36Sopenharmony_ci * @prop_name: A name to postfix to many DT properties, while parsing them. 17162306a36Sopenharmony_ci * @config_clks: Platform specific config_clks() callback. 17262306a36Sopenharmony_ci * @clks: Device's clock handles, for multiple clocks. 17362306a36Sopenharmony_ci * @clk: Device's clock handle, for single clock. 17462306a36Sopenharmony_ci * @clk_count: Number of clocks. 17562306a36Sopenharmony_ci * @config_regulators: Platform specific config_regulators() callback. 17662306a36Sopenharmony_ci * @regulators: Supply regulators 17762306a36Sopenharmony_ci * @regulator_count: Number of power supply regulators. Its value can be -1 17862306a36Sopenharmony_ci * (uninitialized), 0 (no opp-microvolt property) or > 0 (has opp-microvolt 17962306a36Sopenharmony_ci * property). 18062306a36Sopenharmony_ci * @paths: Interconnect path handles 18162306a36Sopenharmony_ci * @path_count: Number of interconnect paths 18262306a36Sopenharmony_ci * @enabled: Set to true if the device's resources are enabled/configured. 18362306a36Sopenharmony_ci * @is_genpd: Marks if the OPP table belongs to a genpd. 18462306a36Sopenharmony_ci * @set_required_opps: Helper responsible to set required OPPs. 18562306a36Sopenharmony_ci * @dentry: debugfs dentry pointer of the real device directory (not links). 18662306a36Sopenharmony_ci * @dentry_name: Name of the real dentry. 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * @voltage_tolerance_v1: In percentage, for v1 bindings only. 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * This is an internal data structure maintaining the link to opps attached to 19162306a36Sopenharmony_ci * a device. This structure is not meant to be shared to users as it is 19262306a36Sopenharmony_ci * meant for book keeping and private to OPP library. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_cistruct opp_table { 19562306a36Sopenharmony_ci struct list_head node, lazy; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci struct blocking_notifier_head head; 19862306a36Sopenharmony_ci struct list_head dev_list; 19962306a36Sopenharmony_ci struct list_head opp_list; 20062306a36Sopenharmony_ci struct kref kref; 20162306a36Sopenharmony_ci struct mutex lock; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci struct device_node *np; 20462306a36Sopenharmony_ci unsigned long clock_latency_ns_max; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* For backward compatibility with v1 bindings */ 20762306a36Sopenharmony_ci unsigned int voltage_tolerance_v1; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci unsigned int parsed_static_opps; 21062306a36Sopenharmony_ci enum opp_table_access shared_opp; 21162306a36Sopenharmony_ci unsigned long rate_clk_single; 21262306a36Sopenharmony_ci struct dev_pm_opp *current_opp; 21362306a36Sopenharmony_ci struct dev_pm_opp *suspend_opp; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci struct mutex genpd_virt_dev_lock; 21662306a36Sopenharmony_ci struct device **genpd_virt_devs; 21762306a36Sopenharmony_ci struct opp_table **required_opp_tables; 21862306a36Sopenharmony_ci unsigned int required_opp_count; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci unsigned int *supported_hw; 22162306a36Sopenharmony_ci unsigned int supported_hw_count; 22262306a36Sopenharmony_ci const char *prop_name; 22362306a36Sopenharmony_ci config_clks_t config_clks; 22462306a36Sopenharmony_ci struct clk **clks; 22562306a36Sopenharmony_ci struct clk *clk; 22662306a36Sopenharmony_ci int clk_count; 22762306a36Sopenharmony_ci config_regulators_t config_regulators; 22862306a36Sopenharmony_ci struct regulator **regulators; 22962306a36Sopenharmony_ci int regulator_count; 23062306a36Sopenharmony_ci struct icc_path **paths; 23162306a36Sopenharmony_ci unsigned int path_count; 23262306a36Sopenharmony_ci bool enabled; 23362306a36Sopenharmony_ci bool is_genpd; 23462306a36Sopenharmony_ci int (*set_required_opps)(struct device *dev, 23562306a36Sopenharmony_ci struct opp_table *opp_table, struct dev_pm_opp *opp, bool scaling_down); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 23862306a36Sopenharmony_ci struct dentry *dentry; 23962306a36Sopenharmony_ci char dentry_name[NAME_MAX]; 24062306a36Sopenharmony_ci#endif 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* Routines internal to opp core */ 24462306a36Sopenharmony_civoid dev_pm_opp_get(struct dev_pm_opp *opp); 24562306a36Sopenharmony_cibool _opp_remove_all_static(struct opp_table *opp_table); 24662306a36Sopenharmony_civoid _get_opp_table_kref(struct opp_table *opp_table); 24762306a36Sopenharmony_ciint _get_opp_count(struct opp_table *opp_table); 24862306a36Sopenharmony_cistruct opp_table *_find_opp_table(struct device *dev); 24962306a36Sopenharmony_cistruct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); 25062306a36Sopenharmony_cistruct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); 25162306a36Sopenharmony_civoid _opp_free(struct dev_pm_opp *opp); 25262306a36Sopenharmony_ciint _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1, struct dev_pm_opp *opp2); 25362306a36Sopenharmony_ciint _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table); 25462306a36Sopenharmony_ciint _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); 25562306a36Sopenharmony_civoid _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu); 25662306a36Sopenharmony_cistruct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk); 25762306a36Sopenharmony_civoid _put_opp_list_kref(struct opp_table *opp_table); 25862306a36Sopenharmony_civoid _required_opps_available(struct dev_pm_opp *opp, int count); 25962306a36Sopenharmony_civoid _update_set_required_opps(struct opp_table *opp_table); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic inline bool lazy_linking_pending(struct opp_table *opp_table) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci return unlikely(!list_empty(&opp_table->lazy)); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci#ifdef CONFIG_OF 26762306a36Sopenharmony_civoid _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index); 26862306a36Sopenharmony_civoid _of_clear_opp_table(struct opp_table *opp_table); 26962306a36Sopenharmony_cistruct opp_table *_managed_opp(struct device *dev, int index); 27062306a36Sopenharmony_civoid _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp); 27162306a36Sopenharmony_ci#else 27262306a36Sopenharmony_cistatic inline void _of_init_opp_table(struct opp_table *opp_table, struct device *dev, int index) {} 27362306a36Sopenharmony_cistatic inline void _of_clear_opp_table(struct opp_table *opp_table) {} 27462306a36Sopenharmony_cistatic inline struct opp_table *_managed_opp(struct device *dev, int index) { return NULL; } 27562306a36Sopenharmony_cistatic inline void _of_clear_opp(struct opp_table *opp_table, struct dev_pm_opp *opp) {} 27662306a36Sopenharmony_ci#endif 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 27962306a36Sopenharmony_civoid opp_debug_remove_one(struct dev_pm_opp *opp); 28062306a36Sopenharmony_civoid opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table); 28162306a36Sopenharmony_civoid opp_debug_register(struct opp_device *opp_dev, struct opp_table *opp_table); 28262306a36Sopenharmony_civoid opp_debug_unregister(struct opp_device *opp_dev, struct opp_table *opp_table); 28362306a36Sopenharmony_ci#else 28462306a36Sopenharmony_cistatic inline void opp_debug_remove_one(struct dev_pm_opp *opp) {} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic inline void opp_debug_create_one(struct dev_pm_opp *opp, 28762306a36Sopenharmony_ci struct opp_table *opp_table) { } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic inline void opp_debug_register(struct opp_device *opp_dev, 29062306a36Sopenharmony_ci struct opp_table *opp_table) { } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic inline void opp_debug_unregister(struct opp_device *opp_dev, 29362306a36Sopenharmony_ci struct opp_table *opp_table) 29462306a36Sopenharmony_ci{ } 29562306a36Sopenharmony_ci#endif /* DEBUG_FS */ 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci#endif /* __DRIVER_OPP_H__ */ 298