18f835497SViresh Kumar // SPDX-License-Identifier: GPL-2.0
28f835497SViresh Kumar
38f835497SViresh Kumar //! Operating performance points.
48f835497SViresh Kumar //!
58f835497SViresh Kumar //! This module provides rust abstractions for interacting with the OPP subsystem.
68f835497SViresh Kumar //!
78f835497SViresh Kumar //! C header: [`include/linux/pm_opp.h`](srctree/include/linux/pm_opp.h)
88f835497SViresh Kumar //!
98f835497SViresh Kumar //! Reference: <https://docs.kernel.org/power/opp.html>
108f835497SViresh Kumar
118f835497SViresh Kumar use crate::{
128f835497SViresh Kumar clk::Hertz,
13d52c7e86SViresh Kumar cpumask::{Cpumask, CpumaskVar},
148f835497SViresh Kumar device::Device,
15ce32e2d4SViresh Kumar error::{code::*, from_err_ptr, from_result, to_result, Error, Result, VTABLE_DEFAULT_ERROR},
168f835497SViresh Kumar ffi::c_ulong,
17ce32e2d4SViresh Kumar prelude::*,
18ce32e2d4SViresh Kumar str::CString,
198f835497SViresh Kumar types::{ARef, AlwaysRefCounted, Opaque},
208f835497SViresh Kumar };
218f835497SViresh Kumar
2214f47156SViresh Kumar #[cfg(CONFIG_CPU_FREQ)]
2314f47156SViresh Kumar /// Frequency table implementation.
2414f47156SViresh Kumar mod freq {
2514f47156SViresh Kumar use super::*;
2614f47156SViresh Kumar use crate::cpufreq;
2714f47156SViresh Kumar use core::ops::Deref;
2814f47156SViresh Kumar
2914f47156SViresh Kumar /// OPP frequency table.
3014f47156SViresh Kumar ///
3114f47156SViresh Kumar /// A [`cpufreq::Table`] created from [`Table`].
3214f47156SViresh Kumar pub struct FreqTable {
3314f47156SViresh Kumar dev: ARef<Device>,
3414f47156SViresh Kumar ptr: *mut bindings::cpufreq_frequency_table,
3514f47156SViresh Kumar }
3614f47156SViresh Kumar
3714f47156SViresh Kumar impl FreqTable {
3814f47156SViresh Kumar /// Creates a new instance of [`FreqTable`] from [`Table`].
new(table: &Table) -> Result<Self>3914f47156SViresh Kumar pub(crate) fn new(table: &Table) -> Result<Self> {
4014f47156SViresh Kumar let mut ptr: *mut bindings::cpufreq_frequency_table = ptr::null_mut();
4114f47156SViresh Kumar
4214f47156SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
4314f47156SViresh Kumar // requirements.
4414f47156SViresh Kumar to_result(unsafe {
4514f47156SViresh Kumar bindings::dev_pm_opp_init_cpufreq_table(table.dev.as_raw(), &mut ptr)
4614f47156SViresh Kumar })?;
4714f47156SViresh Kumar
4814f47156SViresh Kumar Ok(Self {
4914f47156SViresh Kumar dev: table.dev.clone(),
5014f47156SViresh Kumar ptr,
5114f47156SViresh Kumar })
5214f47156SViresh Kumar }
5314f47156SViresh Kumar
5414f47156SViresh Kumar /// Returns a reference to the underlying [`cpufreq::Table`].
5514f47156SViresh Kumar #[inline]
table(&self) -> &cpufreq::Table5614f47156SViresh Kumar fn table(&self) -> &cpufreq::Table {
5714f47156SViresh Kumar // SAFETY: The `ptr` is guaranteed by the C code to be valid.
5814f47156SViresh Kumar unsafe { cpufreq::Table::from_raw(self.ptr) }
5914f47156SViresh Kumar }
6014f47156SViresh Kumar }
6114f47156SViresh Kumar
6214f47156SViresh Kumar impl Deref for FreqTable {
6314f47156SViresh Kumar type Target = cpufreq::Table;
6414f47156SViresh Kumar
6514f47156SViresh Kumar #[inline]
deref(&self) -> &Self::Target6614f47156SViresh Kumar fn deref(&self) -> &Self::Target {
6714f47156SViresh Kumar self.table()
6814f47156SViresh Kumar }
6914f47156SViresh Kumar }
7014f47156SViresh Kumar
7114f47156SViresh Kumar impl Drop for FreqTable {
drop(&mut self)7214f47156SViresh Kumar fn drop(&mut self) {
7314f47156SViresh Kumar // SAFETY: The pointer was created via `dev_pm_opp_init_cpufreq_table`, and is only
7414f47156SViresh Kumar // freed here.
7514f47156SViresh Kumar unsafe {
7614f47156SViresh Kumar bindings::dev_pm_opp_free_cpufreq_table(self.dev.as_raw(), &mut self.as_raw())
7714f47156SViresh Kumar };
7814f47156SViresh Kumar }
7914f47156SViresh Kumar }
8014f47156SViresh Kumar }
8114f47156SViresh Kumar
8214f47156SViresh Kumar #[cfg(CONFIG_CPU_FREQ)]
8314f47156SViresh Kumar pub use freq::FreqTable;
8414f47156SViresh Kumar
85ce32e2d4SViresh Kumar use core::{marker::PhantomData, ptr};
86ce32e2d4SViresh Kumar
87ce32e2d4SViresh Kumar use macros::vtable;
88ce32e2d4SViresh Kumar
89ce32e2d4SViresh Kumar /// Creates a null-terminated slice of pointers to [`Cstring`]s.
to_c_str_array(names: &[CString]) -> Result<KVec<*const u8>>90ce32e2d4SViresh Kumar fn to_c_str_array(names: &[CString]) -> Result<KVec<*const u8>> {
91ce32e2d4SViresh Kumar // Allocated a null-terminated vector of pointers.
92ce32e2d4SViresh Kumar let mut list = KVec::with_capacity(names.len() + 1, GFP_KERNEL)?;
93ce32e2d4SViresh Kumar
94ce32e2d4SViresh Kumar for name in names.iter() {
95ce32e2d4SViresh Kumar list.push(name.as_ptr() as _, GFP_KERNEL)?;
96ce32e2d4SViresh Kumar }
97ce32e2d4SViresh Kumar
98ce32e2d4SViresh Kumar list.push(ptr::null(), GFP_KERNEL)?;
99ce32e2d4SViresh Kumar Ok(list)
100ce32e2d4SViresh Kumar }
1018f835497SViresh Kumar
1028f835497SViresh Kumar /// The voltage unit.
1038f835497SViresh Kumar ///
1048f835497SViresh Kumar /// Represents voltage in microvolts, wrapping a [`c_ulong`] value.
1058f835497SViresh Kumar ///
1068f835497SViresh Kumar /// ## Examples
1078f835497SViresh Kumar ///
1088f835497SViresh Kumar /// ```
1098f835497SViresh Kumar /// use kernel::opp::MicroVolt;
1108f835497SViresh Kumar ///
1118f835497SViresh Kumar /// let raw = 90500;
1128f835497SViresh Kumar /// let volt = MicroVolt(raw);
1138f835497SViresh Kumar ///
1148f835497SViresh Kumar /// assert_eq!(usize::from(volt), raw);
1158f835497SViresh Kumar /// assert_eq!(volt, MicroVolt(raw));
1168f835497SViresh Kumar /// ```
1178f835497SViresh Kumar #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1188f835497SViresh Kumar pub struct MicroVolt(pub c_ulong);
1198f835497SViresh Kumar
1208f835497SViresh Kumar impl From<MicroVolt> for c_ulong {
1218f835497SViresh Kumar #[inline]
from(volt: MicroVolt) -> Self1228f835497SViresh Kumar fn from(volt: MicroVolt) -> Self {
1238f835497SViresh Kumar volt.0
1248f835497SViresh Kumar }
1258f835497SViresh Kumar }
1268f835497SViresh Kumar
1278f835497SViresh Kumar /// The power unit.
1288f835497SViresh Kumar ///
1298f835497SViresh Kumar /// Represents power in microwatts, wrapping a [`c_ulong`] value.
1308f835497SViresh Kumar ///
1318f835497SViresh Kumar /// ## Examples
1328f835497SViresh Kumar ///
1338f835497SViresh Kumar /// ```
1348f835497SViresh Kumar /// use kernel::opp::MicroWatt;
1358f835497SViresh Kumar ///
1368f835497SViresh Kumar /// let raw = 1000000;
1378f835497SViresh Kumar /// let power = MicroWatt(raw);
1388f835497SViresh Kumar ///
1398f835497SViresh Kumar /// assert_eq!(usize::from(power), raw);
1408f835497SViresh Kumar /// assert_eq!(power, MicroWatt(raw));
1418f835497SViresh Kumar /// ```
1428f835497SViresh Kumar #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1438f835497SViresh Kumar pub struct MicroWatt(pub c_ulong);
1448f835497SViresh Kumar
1458f835497SViresh Kumar impl From<MicroWatt> for c_ulong {
1468f835497SViresh Kumar #[inline]
from(power: MicroWatt) -> Self1478f835497SViresh Kumar fn from(power: MicroWatt) -> Self {
1488f835497SViresh Kumar power.0
1498f835497SViresh Kumar }
1508f835497SViresh Kumar }
1518f835497SViresh Kumar
1528f835497SViresh Kumar /// Handle for a dynamically created [`OPP`].
1538f835497SViresh Kumar ///
1548f835497SViresh Kumar /// The associated [`OPP`] is automatically removed when the [`Token`] is dropped.
1558f835497SViresh Kumar ///
1568f835497SViresh Kumar /// ## Examples
1578f835497SViresh Kumar ///
1588f835497SViresh Kumar /// The following example demonstrates how to create an [`OPP`] dynamically.
1598f835497SViresh Kumar ///
1608f835497SViresh Kumar /// ```
1618f835497SViresh Kumar /// use kernel::clk::Hertz;
1628f835497SViresh Kumar /// use kernel::device::Device;
1638f835497SViresh Kumar /// use kernel::error::Result;
1648f835497SViresh Kumar /// use kernel::opp::{Data, MicroVolt, Token};
1658f835497SViresh Kumar /// use kernel::types::ARef;
1668f835497SViresh Kumar ///
1678f835497SViresh Kumar /// fn create_opp(dev: &ARef<Device>, freq: Hertz, volt: MicroVolt, level: u32) -> Result<Token> {
1688f835497SViresh Kumar /// let data = Data::new(freq, volt, level, false);
1698f835497SViresh Kumar ///
1708f835497SViresh Kumar /// // OPP is removed once token goes out of scope.
1718f835497SViresh Kumar /// data.add_opp(dev)
1728f835497SViresh Kumar /// }
1738f835497SViresh Kumar /// ```
1748f835497SViresh Kumar pub struct Token {
1758f835497SViresh Kumar dev: ARef<Device>,
1768f835497SViresh Kumar freq: Hertz,
1778f835497SViresh Kumar }
1788f835497SViresh Kumar
1798f835497SViresh Kumar impl Token {
1808f835497SViresh Kumar /// Dynamically adds an [`OPP`] and returns a [`Token`] that removes it on drop.
new(dev: &ARef<Device>, mut data: Data) -> Result<Self>1818f835497SViresh Kumar fn new(dev: &ARef<Device>, mut data: Data) -> Result<Self> {
1828f835497SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
1838f835497SViresh Kumar // requirements.
1848f835497SViresh Kumar to_result(unsafe { bindings::dev_pm_opp_add_dynamic(dev.as_raw(), &mut data.0) })?;
1858f835497SViresh Kumar Ok(Self {
1868f835497SViresh Kumar dev: dev.clone(),
1878f835497SViresh Kumar freq: data.freq(),
1888f835497SViresh Kumar })
1898f835497SViresh Kumar }
1908f835497SViresh Kumar }
1918f835497SViresh Kumar
1928f835497SViresh Kumar impl Drop for Token {
drop(&mut self)1938f835497SViresh Kumar fn drop(&mut self) {
1948f835497SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
1958f835497SViresh Kumar // requirements.
1968f835497SViresh Kumar unsafe { bindings::dev_pm_opp_remove(self.dev.as_raw(), self.freq.into()) };
1978f835497SViresh Kumar }
1988f835497SViresh Kumar }
1998f835497SViresh Kumar
2008f835497SViresh Kumar /// OPP data.
2018f835497SViresh Kumar ///
2028f835497SViresh Kumar /// Rust abstraction for the C `struct dev_pm_opp_data`, used to define operating performance
2038f835497SViresh Kumar /// points (OPPs) dynamically.
2048f835497SViresh Kumar ///
2058f835497SViresh Kumar /// ## Examples
2068f835497SViresh Kumar ///
2078f835497SViresh Kumar /// The following example demonstrates how to create an [`OPP`] with [`Data`].
2088f835497SViresh Kumar ///
2098f835497SViresh Kumar /// ```
2108f835497SViresh Kumar /// use kernel::clk::Hertz;
2118f835497SViresh Kumar /// use kernel::device::Device;
2128f835497SViresh Kumar /// use kernel::error::Result;
2138f835497SViresh Kumar /// use kernel::opp::{Data, MicroVolt, Token};
2148f835497SViresh Kumar /// use kernel::types::ARef;
2158f835497SViresh Kumar ///
2168f835497SViresh Kumar /// fn create_opp(dev: &ARef<Device>, freq: Hertz, volt: MicroVolt, level: u32) -> Result<Token> {
2178f835497SViresh Kumar /// let data = Data::new(freq, volt, level, false);
2188f835497SViresh Kumar ///
2198f835497SViresh Kumar /// // OPP is removed once token goes out of scope.
2208f835497SViresh Kumar /// data.add_opp(dev)
2218f835497SViresh Kumar /// }
2228f835497SViresh Kumar /// ```
2238f835497SViresh Kumar #[repr(transparent)]
2248f835497SViresh Kumar pub struct Data(bindings::dev_pm_opp_data);
2258f835497SViresh Kumar
2268f835497SViresh Kumar impl Data {
2278f835497SViresh Kumar /// Creates a new instance of [`Data`].
2288f835497SViresh Kumar ///
2298f835497SViresh Kumar /// This can be used to define a dynamic OPP to be added to a device.
new(freq: Hertz, volt: MicroVolt, level: u32, turbo: bool) -> Self2308f835497SViresh Kumar pub fn new(freq: Hertz, volt: MicroVolt, level: u32, turbo: bool) -> Self {
2318f835497SViresh Kumar Self(bindings::dev_pm_opp_data {
2328f835497SViresh Kumar turbo,
2338f835497SViresh Kumar freq: freq.into(),
2348f835497SViresh Kumar u_volt: volt.into(),
2358f835497SViresh Kumar level,
2368f835497SViresh Kumar })
2378f835497SViresh Kumar }
2388f835497SViresh Kumar
2398f835497SViresh Kumar /// Adds an [`OPP`] dynamically.
2408f835497SViresh Kumar ///
2418f835497SViresh Kumar /// Returns a [`Token`] that ensures the OPP is automatically removed
2428f835497SViresh Kumar /// when it goes out of scope.
2438f835497SViresh Kumar #[inline]
add_opp(self, dev: &ARef<Device>) -> Result<Token>2448f835497SViresh Kumar pub fn add_opp(self, dev: &ARef<Device>) -> Result<Token> {
2458f835497SViresh Kumar Token::new(dev, self)
2468f835497SViresh Kumar }
2478f835497SViresh Kumar
2488f835497SViresh Kumar /// Returns the frequency associated with this OPP data.
2498f835497SViresh Kumar #[inline]
freq(&self) -> Hertz2508f835497SViresh Kumar fn freq(&self) -> Hertz {
2518f835497SViresh Kumar Hertz(self.0.freq)
2528f835497SViresh Kumar }
2538f835497SViresh Kumar }
2548f835497SViresh Kumar
255d52c7e86SViresh Kumar /// [`OPP`] search options.
256d52c7e86SViresh Kumar ///
257d52c7e86SViresh Kumar /// ## Examples
258d52c7e86SViresh Kumar ///
259d52c7e86SViresh Kumar /// Defines how to search for an [`OPP`] in a [`Table`] relative to a frequency.
260d52c7e86SViresh Kumar ///
261d52c7e86SViresh Kumar /// ```
262d52c7e86SViresh Kumar /// use kernel::clk::Hertz;
263d52c7e86SViresh Kumar /// use kernel::error::Result;
264d52c7e86SViresh Kumar /// use kernel::opp::{OPP, SearchType, Table};
265d52c7e86SViresh Kumar /// use kernel::types::ARef;
266d52c7e86SViresh Kumar ///
267d52c7e86SViresh Kumar /// fn find_opp(table: &Table, freq: Hertz) -> Result<ARef<OPP>> {
268d52c7e86SViresh Kumar /// let opp = table.opp_from_freq(freq, Some(true), None, SearchType::Exact)?;
269d52c7e86SViresh Kumar ///
270d52c7e86SViresh Kumar /// pr_info!("OPP frequency is: {:?}\n", opp.freq(None));
271d52c7e86SViresh Kumar /// pr_info!("OPP voltage is: {:?}\n", opp.voltage());
272d52c7e86SViresh Kumar /// pr_info!("OPP level is: {}\n", opp.level());
273d52c7e86SViresh Kumar /// pr_info!("OPP power is: {:?}\n", opp.power());
274d52c7e86SViresh Kumar ///
275d52c7e86SViresh Kumar /// Ok(opp)
276d52c7e86SViresh Kumar /// }
277d52c7e86SViresh Kumar /// ```
278d52c7e86SViresh Kumar #[derive(Copy, Clone, Debug, Eq, PartialEq)]
279d52c7e86SViresh Kumar pub enum SearchType {
280d52c7e86SViresh Kumar /// Match the exact frequency.
281d52c7e86SViresh Kumar Exact,
282d52c7e86SViresh Kumar /// Find the highest frequency less than or equal to the given value.
283d52c7e86SViresh Kumar Floor,
284d52c7e86SViresh Kumar /// Find the lowest frequency greater than or equal to the given value.
285d52c7e86SViresh Kumar Ceil,
286d52c7e86SViresh Kumar }
287d52c7e86SViresh Kumar
288ce32e2d4SViresh Kumar /// OPP configuration callbacks.
289ce32e2d4SViresh Kumar ///
290ce32e2d4SViresh Kumar /// Implement this trait to customize OPP clock and regulator setup for your device.
291ce32e2d4SViresh Kumar #[vtable]
292ce32e2d4SViresh Kumar pub trait ConfigOps {
293ce32e2d4SViresh Kumar /// This is typically used to scale clocks when transitioning between OPPs.
294ce32e2d4SViresh Kumar #[inline]
config_clks(_dev: &Device, _table: &Table, _opp: &OPP, _scaling_down: bool) -> Result295ce32e2d4SViresh Kumar fn config_clks(_dev: &Device, _table: &Table, _opp: &OPP, _scaling_down: bool) -> Result {
296ce32e2d4SViresh Kumar build_error!(VTABLE_DEFAULT_ERROR)
297ce32e2d4SViresh Kumar }
298ce32e2d4SViresh Kumar
299ce32e2d4SViresh Kumar /// This provides access to the old and new OPPs, allowing for safe regulator adjustments.
300ce32e2d4SViresh Kumar #[inline]
config_regulators( _dev: &Device, _opp_old: &OPP, _opp_new: &OPP, _data: *mut *mut bindings::regulator, _count: u32, ) -> Result301ce32e2d4SViresh Kumar fn config_regulators(
302ce32e2d4SViresh Kumar _dev: &Device,
303ce32e2d4SViresh Kumar _opp_old: &OPP,
304ce32e2d4SViresh Kumar _opp_new: &OPP,
305ce32e2d4SViresh Kumar _data: *mut *mut bindings::regulator,
306ce32e2d4SViresh Kumar _count: u32,
307ce32e2d4SViresh Kumar ) -> Result {
308ce32e2d4SViresh Kumar build_error!(VTABLE_DEFAULT_ERROR)
309ce32e2d4SViresh Kumar }
310ce32e2d4SViresh Kumar }
311ce32e2d4SViresh Kumar
312ce32e2d4SViresh Kumar /// OPP configuration token.
313ce32e2d4SViresh Kumar ///
314ce32e2d4SViresh Kumar /// Returned by the OPP core when configuration is applied to a [`Device`]. The associated
315ce32e2d4SViresh Kumar /// configuration is automatically cleared when the token is dropped.
316ce32e2d4SViresh Kumar pub struct ConfigToken(i32);
317ce32e2d4SViresh Kumar
318ce32e2d4SViresh Kumar impl Drop for ConfigToken {
drop(&mut self)319ce32e2d4SViresh Kumar fn drop(&mut self) {
320ce32e2d4SViresh Kumar // SAFETY: This is the same token value returned by the C code via `dev_pm_opp_set_config`.
321ce32e2d4SViresh Kumar unsafe { bindings::dev_pm_opp_clear_config(self.0) };
322ce32e2d4SViresh Kumar }
323ce32e2d4SViresh Kumar }
324ce32e2d4SViresh Kumar
325ce32e2d4SViresh Kumar /// OPP configurations.
326ce32e2d4SViresh Kumar ///
327ce32e2d4SViresh Kumar /// Rust abstraction for the C `struct dev_pm_opp_config`.
328ce32e2d4SViresh Kumar ///
329ce32e2d4SViresh Kumar /// ## Examples
330ce32e2d4SViresh Kumar ///
331ce32e2d4SViresh Kumar /// The following example demonstrates how to set OPP property-name configuration for a [`Device`].
332ce32e2d4SViresh Kumar ///
333ce32e2d4SViresh Kumar /// ```
334ce32e2d4SViresh Kumar /// use kernel::device::Device;
335ce32e2d4SViresh Kumar /// use kernel::error::Result;
336ce32e2d4SViresh Kumar /// use kernel::opp::{Config, ConfigOps, ConfigToken};
337ce32e2d4SViresh Kumar /// use kernel::str::CString;
338ce32e2d4SViresh Kumar /// use kernel::types::ARef;
339ce32e2d4SViresh Kumar /// use kernel::macros::vtable;
340ce32e2d4SViresh Kumar ///
341ce32e2d4SViresh Kumar /// #[derive(Default)]
342ce32e2d4SViresh Kumar /// struct Driver;
343ce32e2d4SViresh Kumar ///
344ce32e2d4SViresh Kumar /// #[vtable]
345ce32e2d4SViresh Kumar /// impl ConfigOps for Driver {}
346ce32e2d4SViresh Kumar ///
347ce32e2d4SViresh Kumar /// fn configure(dev: &ARef<Device>) -> Result<ConfigToken> {
348ce32e2d4SViresh Kumar /// let name = CString::try_from_fmt(fmt!("{}", "slow"))?;
349ce32e2d4SViresh Kumar ///
350ce32e2d4SViresh Kumar /// // The OPP configuration is cleared once the [`ConfigToken`] goes out of scope.
351ce32e2d4SViresh Kumar /// Config::<Driver>::new()
352ce32e2d4SViresh Kumar /// .set_prop_name(name)?
353ce32e2d4SViresh Kumar /// .set(dev)
354ce32e2d4SViresh Kumar /// }
355ce32e2d4SViresh Kumar /// ```
356ce32e2d4SViresh Kumar #[derive(Default)]
357ce32e2d4SViresh Kumar pub struct Config<T: ConfigOps>
358ce32e2d4SViresh Kumar where
359ce32e2d4SViresh Kumar T: Default,
360ce32e2d4SViresh Kumar {
361ce32e2d4SViresh Kumar clk_names: Option<KVec<CString>>,
362ce32e2d4SViresh Kumar prop_name: Option<CString>,
363ce32e2d4SViresh Kumar regulator_names: Option<KVec<CString>>,
364ce32e2d4SViresh Kumar supported_hw: Option<KVec<u32>>,
365ce32e2d4SViresh Kumar
366ce32e2d4SViresh Kumar // Tuple containing (required device, index)
367ce32e2d4SViresh Kumar required_dev: Option<(ARef<Device>, u32)>,
368ce32e2d4SViresh Kumar _data: PhantomData<T>,
369ce32e2d4SViresh Kumar }
370ce32e2d4SViresh Kumar
371ce32e2d4SViresh Kumar impl<T: ConfigOps + Default> Config<T> {
372ce32e2d4SViresh Kumar /// Creates a new instance of [`Config`].
373ce32e2d4SViresh Kumar #[inline]
new() -> Self374ce32e2d4SViresh Kumar pub fn new() -> Self {
375ce32e2d4SViresh Kumar Self::default()
376ce32e2d4SViresh Kumar }
377ce32e2d4SViresh Kumar
378ce32e2d4SViresh Kumar /// Initializes clock names.
set_clk_names(mut self, names: KVec<CString>) -> Result<Self>379ce32e2d4SViresh Kumar pub fn set_clk_names(mut self, names: KVec<CString>) -> Result<Self> {
380ce32e2d4SViresh Kumar if self.clk_names.is_some() {
381ce32e2d4SViresh Kumar return Err(EBUSY);
382ce32e2d4SViresh Kumar }
383ce32e2d4SViresh Kumar
384ce32e2d4SViresh Kumar if names.is_empty() {
385ce32e2d4SViresh Kumar return Err(EINVAL);
386ce32e2d4SViresh Kumar }
387ce32e2d4SViresh Kumar
388ce32e2d4SViresh Kumar self.clk_names = Some(names);
389ce32e2d4SViresh Kumar Ok(self)
390ce32e2d4SViresh Kumar }
391ce32e2d4SViresh Kumar
392ce32e2d4SViresh Kumar /// Initializes property name.
set_prop_name(mut self, name: CString) -> Result<Self>393ce32e2d4SViresh Kumar pub fn set_prop_name(mut self, name: CString) -> Result<Self> {
394ce32e2d4SViresh Kumar if self.prop_name.is_some() {
395ce32e2d4SViresh Kumar return Err(EBUSY);
396ce32e2d4SViresh Kumar }
397ce32e2d4SViresh Kumar
398ce32e2d4SViresh Kumar self.prop_name = Some(name);
399ce32e2d4SViresh Kumar Ok(self)
400ce32e2d4SViresh Kumar }
401ce32e2d4SViresh Kumar
402ce32e2d4SViresh Kumar /// Initializes regulator names.
set_regulator_names(mut self, names: KVec<CString>) -> Result<Self>403ce32e2d4SViresh Kumar pub fn set_regulator_names(mut self, names: KVec<CString>) -> Result<Self> {
404ce32e2d4SViresh Kumar if self.regulator_names.is_some() {
405ce32e2d4SViresh Kumar return Err(EBUSY);
406ce32e2d4SViresh Kumar }
407ce32e2d4SViresh Kumar
408ce32e2d4SViresh Kumar if names.is_empty() {
409ce32e2d4SViresh Kumar return Err(EINVAL);
410ce32e2d4SViresh Kumar }
411ce32e2d4SViresh Kumar
412ce32e2d4SViresh Kumar self.regulator_names = Some(names);
413ce32e2d4SViresh Kumar
414ce32e2d4SViresh Kumar Ok(self)
415ce32e2d4SViresh Kumar }
416ce32e2d4SViresh Kumar
417ce32e2d4SViresh Kumar /// Initializes required devices.
set_required_dev(mut self, dev: ARef<Device>, index: u32) -> Result<Self>418ce32e2d4SViresh Kumar pub fn set_required_dev(mut self, dev: ARef<Device>, index: u32) -> Result<Self> {
419ce32e2d4SViresh Kumar if self.required_dev.is_some() {
420ce32e2d4SViresh Kumar return Err(EBUSY);
421ce32e2d4SViresh Kumar }
422ce32e2d4SViresh Kumar
423ce32e2d4SViresh Kumar self.required_dev = Some((dev, index));
424ce32e2d4SViresh Kumar Ok(self)
425ce32e2d4SViresh Kumar }
426ce32e2d4SViresh Kumar
427ce32e2d4SViresh Kumar /// Initializes supported hardware.
set_supported_hw(mut self, hw: KVec<u32>) -> Result<Self>428ce32e2d4SViresh Kumar pub fn set_supported_hw(mut self, hw: KVec<u32>) -> Result<Self> {
429ce32e2d4SViresh Kumar if self.supported_hw.is_some() {
430ce32e2d4SViresh Kumar return Err(EBUSY);
431ce32e2d4SViresh Kumar }
432ce32e2d4SViresh Kumar
433ce32e2d4SViresh Kumar if hw.is_empty() {
434ce32e2d4SViresh Kumar return Err(EINVAL);
435ce32e2d4SViresh Kumar }
436ce32e2d4SViresh Kumar
437ce32e2d4SViresh Kumar self.supported_hw = Some(hw);
438ce32e2d4SViresh Kumar Ok(self)
439ce32e2d4SViresh Kumar }
440ce32e2d4SViresh Kumar
441ce32e2d4SViresh Kumar /// Sets the configuration with the OPP core.
442ce32e2d4SViresh Kumar ///
443ce32e2d4SViresh Kumar /// The returned [`ConfigToken`] will remove the configuration when dropped.
set(self, dev: &Device) -> Result<ConfigToken>444ce32e2d4SViresh Kumar pub fn set(self, dev: &Device) -> Result<ConfigToken> {
445ce32e2d4SViresh Kumar let (_clk_list, clk_names) = match &self.clk_names {
446ce32e2d4SViresh Kumar Some(x) => {
447ce32e2d4SViresh Kumar let list = to_c_str_array(x)?;
448ce32e2d4SViresh Kumar let ptr = list.as_ptr();
449ce32e2d4SViresh Kumar (Some(list), ptr)
450ce32e2d4SViresh Kumar }
451ce32e2d4SViresh Kumar None => (None, ptr::null()),
452ce32e2d4SViresh Kumar };
453ce32e2d4SViresh Kumar
454ce32e2d4SViresh Kumar let (_regulator_list, regulator_names) = match &self.regulator_names {
455ce32e2d4SViresh Kumar Some(x) => {
456ce32e2d4SViresh Kumar let list = to_c_str_array(x)?;
457ce32e2d4SViresh Kumar let ptr = list.as_ptr();
458ce32e2d4SViresh Kumar (Some(list), ptr)
459ce32e2d4SViresh Kumar }
460ce32e2d4SViresh Kumar None => (None, ptr::null()),
461ce32e2d4SViresh Kumar };
462ce32e2d4SViresh Kumar
463ce32e2d4SViresh Kumar let prop_name = self
464ce32e2d4SViresh Kumar .prop_name
465ce32e2d4SViresh Kumar .as_ref()
466ce32e2d4SViresh Kumar .map_or(ptr::null(), |p| p.as_char_ptr());
467ce32e2d4SViresh Kumar
468ce32e2d4SViresh Kumar let (supported_hw, supported_hw_count) = self
469ce32e2d4SViresh Kumar .supported_hw
470ce32e2d4SViresh Kumar .as_ref()
471ce32e2d4SViresh Kumar .map_or((ptr::null(), 0), |hw| (hw.as_ptr(), hw.len() as u32));
472ce32e2d4SViresh Kumar
473ce32e2d4SViresh Kumar let (required_dev, required_dev_index) = self
474ce32e2d4SViresh Kumar .required_dev
475ce32e2d4SViresh Kumar .as_ref()
476ce32e2d4SViresh Kumar .map_or((ptr::null_mut(), 0), |(dev, idx)| (dev.as_raw(), *idx));
477ce32e2d4SViresh Kumar
478ce32e2d4SViresh Kumar let mut config = bindings::dev_pm_opp_config {
479ce32e2d4SViresh Kumar clk_names,
480ce32e2d4SViresh Kumar config_clks: if T::HAS_CONFIG_CLKS {
481ce32e2d4SViresh Kumar Some(Self::config_clks)
482ce32e2d4SViresh Kumar } else {
483ce32e2d4SViresh Kumar None
484ce32e2d4SViresh Kumar },
485ce32e2d4SViresh Kumar prop_name,
486ce32e2d4SViresh Kumar regulator_names,
487ce32e2d4SViresh Kumar config_regulators: if T::HAS_CONFIG_REGULATORS {
488ce32e2d4SViresh Kumar Some(Self::config_regulators)
489ce32e2d4SViresh Kumar } else {
490ce32e2d4SViresh Kumar None
491ce32e2d4SViresh Kumar },
492ce32e2d4SViresh Kumar supported_hw,
493ce32e2d4SViresh Kumar supported_hw_count,
494ce32e2d4SViresh Kumar
495ce32e2d4SViresh Kumar required_dev,
496ce32e2d4SViresh Kumar required_dev_index,
497ce32e2d4SViresh Kumar };
498ce32e2d4SViresh Kumar
499ce32e2d4SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
500ce32e2d4SViresh Kumar // requirements. The OPP core guarantees not to access fields of [`Config`] after this call
501ce32e2d4SViresh Kumar // and so we don't need to save a copy of them for future use.
502ce32e2d4SViresh Kumar let ret = unsafe { bindings::dev_pm_opp_set_config(dev.as_raw(), &mut config) };
503ce32e2d4SViresh Kumar if ret < 0 {
504ce32e2d4SViresh Kumar Err(Error::from_errno(ret))
505ce32e2d4SViresh Kumar } else {
506ce32e2d4SViresh Kumar Ok(ConfigToken(ret))
507ce32e2d4SViresh Kumar }
508ce32e2d4SViresh Kumar }
509ce32e2d4SViresh Kumar
510ce32e2d4SViresh Kumar /// Config's clk callback.
511ce32e2d4SViresh Kumar ///
512ce32e2d4SViresh Kumar /// SAFETY: Called from C. Inputs must be valid pointers.
config_clks( dev: *mut bindings::device, opp_table: *mut bindings::opp_table, opp: *mut bindings::dev_pm_opp, _data: *mut kernel::ffi::c_void, scaling_down: bool, ) -> kernel::ffi::c_int513ce32e2d4SViresh Kumar extern "C" fn config_clks(
514ce32e2d4SViresh Kumar dev: *mut bindings::device,
515ce32e2d4SViresh Kumar opp_table: *mut bindings::opp_table,
516ce32e2d4SViresh Kumar opp: *mut bindings::dev_pm_opp,
517ce32e2d4SViresh Kumar _data: *mut kernel::ffi::c_void,
518ce32e2d4SViresh Kumar scaling_down: bool,
519ce32e2d4SViresh Kumar ) -> kernel::ffi::c_int {
520ce32e2d4SViresh Kumar from_result(|| {
521ce32e2d4SViresh Kumar // SAFETY: 'dev' is guaranteed by the C code to be valid.
522ce32e2d4SViresh Kumar let dev = unsafe { Device::get_device(dev) };
523ce32e2d4SViresh Kumar T::config_clks(
524ce32e2d4SViresh Kumar &dev,
525ce32e2d4SViresh Kumar // SAFETY: 'opp_table' is guaranteed by the C code to be valid.
526ce32e2d4SViresh Kumar &unsafe { Table::from_raw_table(opp_table, &dev) },
527ce32e2d4SViresh Kumar // SAFETY: 'opp' is guaranteed by the C code to be valid.
528ce32e2d4SViresh Kumar unsafe { OPP::from_raw_opp(opp)? },
529ce32e2d4SViresh Kumar scaling_down,
530ce32e2d4SViresh Kumar )
531ce32e2d4SViresh Kumar .map(|()| 0)
532ce32e2d4SViresh Kumar })
533ce32e2d4SViresh Kumar }
534ce32e2d4SViresh Kumar
535ce32e2d4SViresh Kumar /// Config's regulator callback.
536ce32e2d4SViresh Kumar ///
537ce32e2d4SViresh Kumar /// SAFETY: Called from C. Inputs must be valid pointers.
config_regulators( dev: *mut bindings::device, old_opp: *mut bindings::dev_pm_opp, new_opp: *mut bindings::dev_pm_opp, regulators: *mut *mut bindings::regulator, count: kernel::ffi::c_uint, ) -> kernel::ffi::c_int538ce32e2d4SViresh Kumar extern "C" fn config_regulators(
539ce32e2d4SViresh Kumar dev: *mut bindings::device,
540ce32e2d4SViresh Kumar old_opp: *mut bindings::dev_pm_opp,
541ce32e2d4SViresh Kumar new_opp: *mut bindings::dev_pm_opp,
542ce32e2d4SViresh Kumar regulators: *mut *mut bindings::regulator,
543ce32e2d4SViresh Kumar count: kernel::ffi::c_uint,
544ce32e2d4SViresh Kumar ) -> kernel::ffi::c_int {
545ce32e2d4SViresh Kumar from_result(|| {
546ce32e2d4SViresh Kumar // SAFETY: 'dev' is guaranteed by the C code to be valid.
547ce32e2d4SViresh Kumar let dev = unsafe { Device::get_device(dev) };
548ce32e2d4SViresh Kumar T::config_regulators(
549ce32e2d4SViresh Kumar &dev,
550ce32e2d4SViresh Kumar // SAFETY: 'old_opp' is guaranteed by the C code to be valid.
551ce32e2d4SViresh Kumar unsafe { OPP::from_raw_opp(old_opp)? },
552ce32e2d4SViresh Kumar // SAFETY: 'new_opp' is guaranteed by the C code to be valid.
553ce32e2d4SViresh Kumar unsafe { OPP::from_raw_opp(new_opp)? },
554ce32e2d4SViresh Kumar regulators,
555ce32e2d4SViresh Kumar count,
556ce32e2d4SViresh Kumar )
557ce32e2d4SViresh Kumar .map(|()| 0)
558ce32e2d4SViresh Kumar })
559ce32e2d4SViresh Kumar }
560ce32e2d4SViresh Kumar }
561ce32e2d4SViresh Kumar
562d52c7e86SViresh Kumar /// A reference-counted OPP table.
563d52c7e86SViresh Kumar ///
564d52c7e86SViresh Kumar /// Rust abstraction for the C `struct opp_table`.
565d52c7e86SViresh Kumar ///
566d52c7e86SViresh Kumar /// # Invariants
567d52c7e86SViresh Kumar ///
568d52c7e86SViresh Kumar /// The pointer stored in `Self` is non-null and valid for the lifetime of the [`Table`].
569d52c7e86SViresh Kumar ///
570d52c7e86SViresh Kumar /// Instances of this type are reference-counted.
571d52c7e86SViresh Kumar ///
572d52c7e86SViresh Kumar /// ## Examples
573d52c7e86SViresh Kumar ///
574d52c7e86SViresh Kumar /// The following example demonstrates how to get OPP [`Table`] for a [`Cpumask`] and set its
575d52c7e86SViresh Kumar /// frequency.
576d52c7e86SViresh Kumar ///
577d52c7e86SViresh Kumar /// ```
578*15bc5c00SViresh Kumar /// # #![cfg(CONFIG_OF)]
579d52c7e86SViresh Kumar /// use kernel::clk::Hertz;
580d52c7e86SViresh Kumar /// use kernel::cpumask::Cpumask;
581d52c7e86SViresh Kumar /// use kernel::device::Device;
582d52c7e86SViresh Kumar /// use kernel::error::Result;
583d52c7e86SViresh Kumar /// use kernel::opp::Table;
584d52c7e86SViresh Kumar /// use kernel::types::ARef;
585d52c7e86SViresh Kumar ///
586d52c7e86SViresh Kumar /// fn get_table(dev: &ARef<Device>, mask: &mut Cpumask, freq: Hertz) -> Result<Table> {
587d52c7e86SViresh Kumar /// let mut opp_table = Table::from_of_cpumask(dev, mask)?;
588d52c7e86SViresh Kumar ///
589d52c7e86SViresh Kumar /// if opp_table.opp_count()? == 0 {
590d52c7e86SViresh Kumar /// return Err(EINVAL);
591d52c7e86SViresh Kumar /// }
592d52c7e86SViresh Kumar ///
593d52c7e86SViresh Kumar /// pr_info!("Max transition latency is: {} ns\n", opp_table.max_transition_latency_ns());
594d52c7e86SViresh Kumar /// pr_info!("Suspend frequency is: {:?}\n", opp_table.suspend_freq());
595d52c7e86SViresh Kumar ///
596d52c7e86SViresh Kumar /// opp_table.set_rate(freq)?;
597d52c7e86SViresh Kumar /// Ok(opp_table)
598d52c7e86SViresh Kumar /// }
599d52c7e86SViresh Kumar /// ```
600d52c7e86SViresh Kumar pub struct Table {
601d52c7e86SViresh Kumar ptr: *mut bindings::opp_table,
602d52c7e86SViresh Kumar dev: ARef<Device>,
603d52c7e86SViresh Kumar #[allow(dead_code)]
604d52c7e86SViresh Kumar em: bool,
605d52c7e86SViresh Kumar #[allow(dead_code)]
606d52c7e86SViresh Kumar of: bool,
607d52c7e86SViresh Kumar cpus: Option<CpumaskVar>,
608d52c7e86SViresh Kumar }
609d52c7e86SViresh Kumar
610d52c7e86SViresh Kumar /// SAFETY: It is okay to send ownership of [`Table`] across thread boundaries.
611d52c7e86SViresh Kumar unsafe impl Send for Table {}
612d52c7e86SViresh Kumar
613d52c7e86SViresh Kumar /// SAFETY: It is okay to access [`Table`] through shared references from other threads because
614d52c7e86SViresh Kumar /// we're either accessing properties that don't change or that are properly synchronised by C code.
615d52c7e86SViresh Kumar unsafe impl Sync for Table {}
616d52c7e86SViresh Kumar
617d52c7e86SViresh Kumar impl Table {
618d52c7e86SViresh Kumar /// Creates a new reference-counted [`Table`] from a raw pointer.
619d52c7e86SViresh Kumar ///
620d52c7e86SViresh Kumar /// # Safety
621d52c7e86SViresh Kumar ///
622d52c7e86SViresh Kumar /// Callers must ensure that `ptr` is valid and non-null.
from_raw_table(ptr: *mut bindings::opp_table, dev: &ARef<Device>) -> Self623d52c7e86SViresh Kumar unsafe fn from_raw_table(ptr: *mut bindings::opp_table, dev: &ARef<Device>) -> Self {
624d52c7e86SViresh Kumar // SAFETY: By the safety requirements, ptr is valid and its refcount will be incremented.
625d52c7e86SViresh Kumar //
626d52c7e86SViresh Kumar // INVARIANT: The reference-count is decremented when [`Table`] goes out of scope.
627d52c7e86SViresh Kumar unsafe { bindings::dev_pm_opp_get_opp_table_ref(ptr) };
628d52c7e86SViresh Kumar
629d52c7e86SViresh Kumar Self {
630d52c7e86SViresh Kumar ptr,
631d52c7e86SViresh Kumar dev: dev.clone(),
632d52c7e86SViresh Kumar em: false,
633d52c7e86SViresh Kumar of: false,
634d52c7e86SViresh Kumar cpus: None,
635d52c7e86SViresh Kumar }
636d52c7e86SViresh Kumar }
637d52c7e86SViresh Kumar
638d52c7e86SViresh Kumar /// Creates a new reference-counted [`Table`] instance for a [`Device`].
from_dev(dev: &Device) -> Result<Self>639d52c7e86SViresh Kumar pub fn from_dev(dev: &Device) -> Result<Self> {
640d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of the [`Device`] and its safety
641d52c7e86SViresh Kumar // requirements.
642d52c7e86SViresh Kumar //
643d52c7e86SViresh Kumar // INVARIANT: The reference-count is incremented by the C code and is decremented when
644d52c7e86SViresh Kumar // [`Table`] goes out of scope.
645d52c7e86SViresh Kumar let ptr = from_err_ptr(unsafe { bindings::dev_pm_opp_get_opp_table(dev.as_raw()) })?;
646d52c7e86SViresh Kumar
647d52c7e86SViresh Kumar Ok(Self {
648d52c7e86SViresh Kumar ptr,
649d52c7e86SViresh Kumar dev: dev.into(),
650d52c7e86SViresh Kumar em: false,
651d52c7e86SViresh Kumar of: false,
652d52c7e86SViresh Kumar cpus: None,
653d52c7e86SViresh Kumar })
654d52c7e86SViresh Kumar }
655d52c7e86SViresh Kumar
656d52c7e86SViresh Kumar /// Creates a new reference-counted [`Table`] instance for a [`Device`] based on device tree
657d52c7e86SViresh Kumar /// entries.
658d52c7e86SViresh Kumar #[cfg(CONFIG_OF)]
from_of(dev: &ARef<Device>, index: i32) -> Result<Self>659d52c7e86SViresh Kumar pub fn from_of(dev: &ARef<Device>, index: i32) -> Result<Self> {
660d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of the [`Device`] and its safety
661d52c7e86SViresh Kumar // requirements.
662d52c7e86SViresh Kumar //
663d52c7e86SViresh Kumar // INVARIANT: The reference-count is incremented by the C code and is decremented when
664d52c7e86SViresh Kumar // [`Table`] goes out of scope.
665d52c7e86SViresh Kumar to_result(unsafe { bindings::dev_pm_opp_of_add_table_indexed(dev.as_raw(), index) })?;
666d52c7e86SViresh Kumar
667d52c7e86SViresh Kumar // Get the newly created [`Table`].
668d52c7e86SViresh Kumar let mut table = Self::from_dev(dev)?;
669d52c7e86SViresh Kumar table.of = true;
670d52c7e86SViresh Kumar
671d52c7e86SViresh Kumar Ok(table)
672d52c7e86SViresh Kumar }
673d52c7e86SViresh Kumar
674d52c7e86SViresh Kumar /// Remove device tree based [`Table`].
675d52c7e86SViresh Kumar #[cfg(CONFIG_OF)]
676d52c7e86SViresh Kumar #[inline]
remove_of(&self)677d52c7e86SViresh Kumar fn remove_of(&self) {
678d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of the [`Device`] and its safety
679d52c7e86SViresh Kumar // requirements. We took the reference from [`from_of`] earlier, it is safe to drop the
680d52c7e86SViresh Kumar // same now.
681d52c7e86SViresh Kumar unsafe { bindings::dev_pm_opp_of_remove_table(self.dev.as_raw()) };
682d52c7e86SViresh Kumar }
683d52c7e86SViresh Kumar
684d52c7e86SViresh Kumar /// Creates a new reference-counted [`Table`] instance for a [`Cpumask`] based on device tree
685d52c7e86SViresh Kumar /// entries.
686d52c7e86SViresh Kumar #[cfg(CONFIG_OF)]
from_of_cpumask(dev: &Device, cpumask: &mut Cpumask) -> Result<Self>687d52c7e86SViresh Kumar pub fn from_of_cpumask(dev: &Device, cpumask: &mut Cpumask) -> Result<Self> {
688d52c7e86SViresh Kumar // SAFETY: The cpumask is valid and the returned pointer will be owned by the [`Table`]
689d52c7e86SViresh Kumar // instance.
690d52c7e86SViresh Kumar //
691d52c7e86SViresh Kumar // INVARIANT: The reference-count is incremented by the C code and is decremented when
692d52c7e86SViresh Kumar // [`Table`] goes out of scope.
693d52c7e86SViresh Kumar to_result(unsafe { bindings::dev_pm_opp_of_cpumask_add_table(cpumask.as_raw()) })?;
694d52c7e86SViresh Kumar
695d52c7e86SViresh Kumar // Fetch the newly created table.
696d52c7e86SViresh Kumar let mut table = Self::from_dev(dev)?;
697d52c7e86SViresh Kumar table.cpus = Some(CpumaskVar::try_clone(cpumask)?);
698d52c7e86SViresh Kumar
699d52c7e86SViresh Kumar Ok(table)
700d52c7e86SViresh Kumar }
701d52c7e86SViresh Kumar
702d52c7e86SViresh Kumar /// Remove device tree based [`Table`] for a [`Cpumask`].
703d52c7e86SViresh Kumar #[cfg(CONFIG_OF)]
704d52c7e86SViresh Kumar #[inline]
remove_of_cpumask(&self, cpumask: &Cpumask)705d52c7e86SViresh Kumar fn remove_of_cpumask(&self, cpumask: &Cpumask) {
706d52c7e86SViresh Kumar // SAFETY: The cpumask is valid and we took the reference from [`from_of_cpumask`] earlier,
707d52c7e86SViresh Kumar // it is safe to drop the same now.
708d52c7e86SViresh Kumar unsafe { bindings::dev_pm_opp_of_cpumask_remove_table(cpumask.as_raw()) };
709d52c7e86SViresh Kumar }
710d52c7e86SViresh Kumar
711d52c7e86SViresh Kumar /// Returns the number of [`OPP`]s in the [`Table`].
opp_count(&self) -> Result<u32>712d52c7e86SViresh Kumar pub fn opp_count(&self) -> Result<u32> {
713d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
714d52c7e86SViresh Kumar // requirements.
715d52c7e86SViresh Kumar let ret = unsafe { bindings::dev_pm_opp_get_opp_count(self.dev.as_raw()) };
716d52c7e86SViresh Kumar if ret < 0 {
717d52c7e86SViresh Kumar Err(Error::from_errno(ret))
718d52c7e86SViresh Kumar } else {
719d52c7e86SViresh Kumar Ok(ret as u32)
720d52c7e86SViresh Kumar }
721d52c7e86SViresh Kumar }
722d52c7e86SViresh Kumar
723d52c7e86SViresh Kumar /// Returns max clock latency (in nanoseconds) of the [`OPP`]s in the [`Table`].
724d52c7e86SViresh Kumar #[inline]
max_clock_latency_ns(&self) -> usize725d52c7e86SViresh Kumar pub fn max_clock_latency_ns(&self) -> usize {
726d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
727d52c7e86SViresh Kumar // requirements.
728d52c7e86SViresh Kumar unsafe { bindings::dev_pm_opp_get_max_clock_latency(self.dev.as_raw()) }
729d52c7e86SViresh Kumar }
730d52c7e86SViresh Kumar
731d52c7e86SViresh Kumar /// Returns max volt latency (in nanoseconds) of the [`OPP`]s in the [`Table`].
732d52c7e86SViresh Kumar #[inline]
max_volt_latency_ns(&self) -> usize733d52c7e86SViresh Kumar pub fn max_volt_latency_ns(&self) -> usize {
734d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
735d52c7e86SViresh Kumar // requirements.
736d52c7e86SViresh Kumar unsafe { bindings::dev_pm_opp_get_max_volt_latency(self.dev.as_raw()) }
737d52c7e86SViresh Kumar }
738d52c7e86SViresh Kumar
739d52c7e86SViresh Kumar /// Returns max transition latency (in nanoseconds) of the [`OPP`]s in the [`Table`].
740d52c7e86SViresh Kumar #[inline]
max_transition_latency_ns(&self) -> usize741d52c7e86SViresh Kumar pub fn max_transition_latency_ns(&self) -> usize {
742d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
743d52c7e86SViresh Kumar // requirements.
744d52c7e86SViresh Kumar unsafe { bindings::dev_pm_opp_get_max_transition_latency(self.dev.as_raw()) }
745d52c7e86SViresh Kumar }
746d52c7e86SViresh Kumar
747d52c7e86SViresh Kumar /// Returns the suspend [`OPP`]'s frequency.
748d52c7e86SViresh Kumar #[inline]
suspend_freq(&self) -> Hertz749d52c7e86SViresh Kumar pub fn suspend_freq(&self) -> Hertz {
750d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
751d52c7e86SViresh Kumar // requirements.
752d52c7e86SViresh Kumar Hertz(unsafe { bindings::dev_pm_opp_get_suspend_opp_freq(self.dev.as_raw()) })
753d52c7e86SViresh Kumar }
754d52c7e86SViresh Kumar
755d52c7e86SViresh Kumar /// Synchronizes regulators used by the [`Table`].
756d52c7e86SViresh Kumar #[inline]
sync_regulators(&self) -> Result757d52c7e86SViresh Kumar pub fn sync_regulators(&self) -> Result {
758d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
759d52c7e86SViresh Kumar // requirements.
760d52c7e86SViresh Kumar to_result(unsafe { bindings::dev_pm_opp_sync_regulators(self.dev.as_raw()) })
761d52c7e86SViresh Kumar }
762d52c7e86SViresh Kumar
763d52c7e86SViresh Kumar /// Gets sharing CPUs.
764d52c7e86SViresh Kumar #[inline]
sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result765d52c7e86SViresh Kumar pub fn sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result {
766d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
767d52c7e86SViresh Kumar // requirements.
768d52c7e86SViresh Kumar to_result(unsafe { bindings::dev_pm_opp_get_sharing_cpus(dev.as_raw(), cpumask.as_raw()) })
769d52c7e86SViresh Kumar }
770d52c7e86SViresh Kumar
771d52c7e86SViresh Kumar /// Sets sharing CPUs.
set_sharing_cpus(&mut self, cpumask: &mut Cpumask) -> Result772d52c7e86SViresh Kumar pub fn set_sharing_cpus(&mut self, cpumask: &mut Cpumask) -> Result {
773d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
774d52c7e86SViresh Kumar // requirements.
775d52c7e86SViresh Kumar to_result(unsafe {
776d52c7e86SViresh Kumar bindings::dev_pm_opp_set_sharing_cpus(self.dev.as_raw(), cpumask.as_raw())
777d52c7e86SViresh Kumar })?;
778d52c7e86SViresh Kumar
779d52c7e86SViresh Kumar if let Some(mask) = self.cpus.as_mut() {
780d52c7e86SViresh Kumar // Update the cpumask as this will be used while removing the table.
781d52c7e86SViresh Kumar cpumask.copy(mask);
782d52c7e86SViresh Kumar }
783d52c7e86SViresh Kumar
784d52c7e86SViresh Kumar Ok(())
785d52c7e86SViresh Kumar }
786d52c7e86SViresh Kumar
787d52c7e86SViresh Kumar /// Gets sharing CPUs from device tree.
788d52c7e86SViresh Kumar #[cfg(CONFIG_OF)]
789d52c7e86SViresh Kumar #[inline]
of_sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result790d52c7e86SViresh Kumar pub fn of_sharing_cpus(dev: &Device, cpumask: &mut Cpumask) -> Result {
791d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
792d52c7e86SViresh Kumar // requirements.
793d52c7e86SViresh Kumar to_result(unsafe {
794d52c7e86SViresh Kumar bindings::dev_pm_opp_of_get_sharing_cpus(dev.as_raw(), cpumask.as_raw())
795d52c7e86SViresh Kumar })
796d52c7e86SViresh Kumar }
797d52c7e86SViresh Kumar
798d52c7e86SViresh Kumar /// Updates the voltage value for an [`OPP`].
799d52c7e86SViresh Kumar #[inline]
adjust_voltage( &self, freq: Hertz, volt: MicroVolt, volt_min: MicroVolt, volt_max: MicroVolt, ) -> Result800d52c7e86SViresh Kumar pub fn adjust_voltage(
801d52c7e86SViresh Kumar &self,
802d52c7e86SViresh Kumar freq: Hertz,
803d52c7e86SViresh Kumar volt: MicroVolt,
804d52c7e86SViresh Kumar volt_min: MicroVolt,
805d52c7e86SViresh Kumar volt_max: MicroVolt,
806d52c7e86SViresh Kumar ) -> Result {
807d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
808d52c7e86SViresh Kumar // requirements.
809d52c7e86SViresh Kumar to_result(unsafe {
810d52c7e86SViresh Kumar bindings::dev_pm_opp_adjust_voltage(
811d52c7e86SViresh Kumar self.dev.as_raw(),
812d52c7e86SViresh Kumar freq.into(),
813d52c7e86SViresh Kumar volt.into(),
814d52c7e86SViresh Kumar volt_min.into(),
815d52c7e86SViresh Kumar volt_max.into(),
816d52c7e86SViresh Kumar )
817d52c7e86SViresh Kumar })
818d52c7e86SViresh Kumar }
819d52c7e86SViresh Kumar
82014f47156SViresh Kumar /// Creates [`FreqTable`] from [`Table`].
82114f47156SViresh Kumar #[cfg(CONFIG_CPU_FREQ)]
82214f47156SViresh Kumar #[inline]
cpufreq_table(&mut self) -> Result<FreqTable>82314f47156SViresh Kumar pub fn cpufreq_table(&mut self) -> Result<FreqTable> {
82414f47156SViresh Kumar FreqTable::new(self)
82514f47156SViresh Kumar }
82614f47156SViresh Kumar
827d52c7e86SViresh Kumar /// Configures device with [`OPP`] matching the frequency value.
828d52c7e86SViresh Kumar #[inline]
set_rate(&self, freq: Hertz) -> Result829d52c7e86SViresh Kumar pub fn set_rate(&self, freq: Hertz) -> Result {
830d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
831d52c7e86SViresh Kumar // requirements.
832d52c7e86SViresh Kumar to_result(unsafe { bindings::dev_pm_opp_set_rate(self.dev.as_raw(), freq.into()) })
833d52c7e86SViresh Kumar }
834d52c7e86SViresh Kumar
835d52c7e86SViresh Kumar /// Configures device with [`OPP`].
836d52c7e86SViresh Kumar #[inline]
set_opp(&self, opp: &OPP) -> Result837d52c7e86SViresh Kumar pub fn set_opp(&self, opp: &OPP) -> Result {
838d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
839d52c7e86SViresh Kumar // requirements.
840d52c7e86SViresh Kumar to_result(unsafe { bindings::dev_pm_opp_set_opp(self.dev.as_raw(), opp.as_raw()) })
841d52c7e86SViresh Kumar }
842d52c7e86SViresh Kumar
843d52c7e86SViresh Kumar /// Finds [`OPP`] based on frequency.
opp_from_freq( &self, freq: Hertz, available: Option<bool>, index: Option<u32>, stype: SearchType, ) -> Result<ARef<OPP>>844d52c7e86SViresh Kumar pub fn opp_from_freq(
845d52c7e86SViresh Kumar &self,
846d52c7e86SViresh Kumar freq: Hertz,
847d52c7e86SViresh Kumar available: Option<bool>,
848d52c7e86SViresh Kumar index: Option<u32>,
849d52c7e86SViresh Kumar stype: SearchType,
850d52c7e86SViresh Kumar ) -> Result<ARef<OPP>> {
851d52c7e86SViresh Kumar let raw_dev = self.dev.as_raw();
852d52c7e86SViresh Kumar let index = index.unwrap_or(0);
853d52c7e86SViresh Kumar let mut rate = freq.into();
854d52c7e86SViresh Kumar
855d52c7e86SViresh Kumar let ptr = from_err_ptr(match stype {
856d52c7e86SViresh Kumar SearchType::Exact => {
857d52c7e86SViresh Kumar if let Some(available) = available {
858d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and
859d52c7e86SViresh Kumar // its safety requirements. The returned pointer will be owned by the new
860d52c7e86SViresh Kumar // [`OPP`] instance.
861d52c7e86SViresh Kumar unsafe {
862d52c7e86SViresh Kumar bindings::dev_pm_opp_find_freq_exact_indexed(
863d52c7e86SViresh Kumar raw_dev, rate, index, available,
864d52c7e86SViresh Kumar )
865d52c7e86SViresh Kumar }
866d52c7e86SViresh Kumar } else {
867d52c7e86SViresh Kumar return Err(EINVAL);
868d52c7e86SViresh Kumar }
869d52c7e86SViresh Kumar }
870d52c7e86SViresh Kumar
871d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
872d52c7e86SViresh Kumar // requirements. The returned pointer will be owned by the new [`OPP`] instance.
873d52c7e86SViresh Kumar SearchType::Ceil => unsafe {
874d52c7e86SViresh Kumar bindings::dev_pm_opp_find_freq_ceil_indexed(raw_dev, &mut rate, index)
875d52c7e86SViresh Kumar },
876d52c7e86SViresh Kumar
877d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
878d52c7e86SViresh Kumar // requirements. The returned pointer will be owned by the new [`OPP`] instance.
879d52c7e86SViresh Kumar SearchType::Floor => unsafe {
880d52c7e86SViresh Kumar bindings::dev_pm_opp_find_freq_floor_indexed(raw_dev, &mut rate, index)
881d52c7e86SViresh Kumar },
882d52c7e86SViresh Kumar })?;
883d52c7e86SViresh Kumar
884d52c7e86SViresh Kumar // SAFETY: The `ptr` is guaranteed by the C code to be valid.
885d52c7e86SViresh Kumar unsafe { OPP::from_raw_opp_owned(ptr) }
886d52c7e86SViresh Kumar }
887d52c7e86SViresh Kumar
888d52c7e86SViresh Kumar /// Finds [`OPP`] based on level.
opp_from_level(&self, mut level: u32, stype: SearchType) -> Result<ARef<OPP>>889d52c7e86SViresh Kumar pub fn opp_from_level(&self, mut level: u32, stype: SearchType) -> Result<ARef<OPP>> {
890d52c7e86SViresh Kumar let raw_dev = self.dev.as_raw();
891d52c7e86SViresh Kumar
892d52c7e86SViresh Kumar let ptr = from_err_ptr(match stype {
893d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
894d52c7e86SViresh Kumar // requirements. The returned pointer will be owned by the new [`OPP`] instance.
895d52c7e86SViresh Kumar SearchType::Exact => unsafe { bindings::dev_pm_opp_find_level_exact(raw_dev, level) },
896d52c7e86SViresh Kumar
897d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
898d52c7e86SViresh Kumar // requirements. The returned pointer will be owned by the new [`OPP`] instance.
899d52c7e86SViresh Kumar SearchType::Ceil => unsafe {
900d52c7e86SViresh Kumar bindings::dev_pm_opp_find_level_ceil(raw_dev, &mut level)
901d52c7e86SViresh Kumar },
902d52c7e86SViresh Kumar
903d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
904d52c7e86SViresh Kumar // requirements. The returned pointer will be owned by the new [`OPP`] instance.
905d52c7e86SViresh Kumar SearchType::Floor => unsafe {
906d52c7e86SViresh Kumar bindings::dev_pm_opp_find_level_floor(raw_dev, &mut level)
907d52c7e86SViresh Kumar },
908d52c7e86SViresh Kumar })?;
909d52c7e86SViresh Kumar
910d52c7e86SViresh Kumar // SAFETY: The `ptr` is guaranteed by the C code to be valid.
911d52c7e86SViresh Kumar unsafe { OPP::from_raw_opp_owned(ptr) }
912d52c7e86SViresh Kumar }
913d52c7e86SViresh Kumar
914d52c7e86SViresh Kumar /// Finds [`OPP`] based on bandwidth.
opp_from_bw(&self, mut bw: u32, index: i32, stype: SearchType) -> Result<ARef<OPP>>915d52c7e86SViresh Kumar pub fn opp_from_bw(&self, mut bw: u32, index: i32, stype: SearchType) -> Result<ARef<OPP>> {
916d52c7e86SViresh Kumar let raw_dev = self.dev.as_raw();
917d52c7e86SViresh Kumar
918d52c7e86SViresh Kumar let ptr = from_err_ptr(match stype {
919d52c7e86SViresh Kumar // The OPP core doesn't support this yet.
920d52c7e86SViresh Kumar SearchType::Exact => return Err(EINVAL),
921d52c7e86SViresh Kumar
922d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
923d52c7e86SViresh Kumar // requirements. The returned pointer will be owned by the new [`OPP`] instance.
924d52c7e86SViresh Kumar SearchType::Ceil => unsafe {
925d52c7e86SViresh Kumar bindings::dev_pm_opp_find_bw_ceil(raw_dev, &mut bw, index)
926d52c7e86SViresh Kumar },
927d52c7e86SViresh Kumar
928d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
929d52c7e86SViresh Kumar // requirements. The returned pointer will be owned by the new [`OPP`] instance.
930d52c7e86SViresh Kumar SearchType::Floor => unsafe {
931d52c7e86SViresh Kumar bindings::dev_pm_opp_find_bw_floor(raw_dev, &mut bw, index)
932d52c7e86SViresh Kumar },
933d52c7e86SViresh Kumar })?;
934d52c7e86SViresh Kumar
935d52c7e86SViresh Kumar // SAFETY: The `ptr` is guaranteed by the C code to be valid.
936d52c7e86SViresh Kumar unsafe { OPP::from_raw_opp_owned(ptr) }
937d52c7e86SViresh Kumar }
938d52c7e86SViresh Kumar
939d52c7e86SViresh Kumar /// Enables the [`OPP`].
940d52c7e86SViresh Kumar #[inline]
enable_opp(&self, freq: Hertz) -> Result941d52c7e86SViresh Kumar pub fn enable_opp(&self, freq: Hertz) -> Result {
942d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
943d52c7e86SViresh Kumar // requirements.
944d52c7e86SViresh Kumar to_result(unsafe { bindings::dev_pm_opp_enable(self.dev.as_raw(), freq.into()) })
945d52c7e86SViresh Kumar }
946d52c7e86SViresh Kumar
947d52c7e86SViresh Kumar /// Disables the [`OPP`].
948d52c7e86SViresh Kumar #[inline]
disable_opp(&self, freq: Hertz) -> Result949d52c7e86SViresh Kumar pub fn disable_opp(&self, freq: Hertz) -> Result {
950d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
951d52c7e86SViresh Kumar // requirements.
952d52c7e86SViresh Kumar to_result(unsafe { bindings::dev_pm_opp_disable(self.dev.as_raw(), freq.into()) })
953d52c7e86SViresh Kumar }
954d52c7e86SViresh Kumar
955d52c7e86SViresh Kumar /// Registers with the Energy model.
956d52c7e86SViresh Kumar #[cfg(CONFIG_OF)]
of_register_em(&mut self, cpumask: &mut Cpumask) -> Result957d52c7e86SViresh Kumar pub fn of_register_em(&mut self, cpumask: &mut Cpumask) -> Result {
958d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
959d52c7e86SViresh Kumar // requirements.
960d52c7e86SViresh Kumar to_result(unsafe {
961d52c7e86SViresh Kumar bindings::dev_pm_opp_of_register_em(self.dev.as_raw(), cpumask.as_raw())
962d52c7e86SViresh Kumar })?;
963d52c7e86SViresh Kumar
964d52c7e86SViresh Kumar self.em = true;
965d52c7e86SViresh Kumar Ok(())
966d52c7e86SViresh Kumar }
967d52c7e86SViresh Kumar
968d52c7e86SViresh Kumar /// Unregisters with the Energy model.
969d52c7e86SViresh Kumar #[cfg(all(CONFIG_OF, CONFIG_ENERGY_MODEL))]
970d52c7e86SViresh Kumar #[inline]
of_unregister_em(&self)971d52c7e86SViresh Kumar fn of_unregister_em(&self) {
972d52c7e86SViresh Kumar // SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
973d52c7e86SViresh Kumar // requirements. We registered with the EM framework earlier, it is safe to unregister now.
974d52c7e86SViresh Kumar unsafe { bindings::em_dev_unregister_perf_domain(self.dev.as_raw()) };
975d52c7e86SViresh Kumar }
976d52c7e86SViresh Kumar }
977d52c7e86SViresh Kumar
978d52c7e86SViresh Kumar impl Drop for Table {
drop(&mut self)979d52c7e86SViresh Kumar fn drop(&mut self) {
980d52c7e86SViresh Kumar // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe
981d52c7e86SViresh Kumar // to relinquish it now.
982d52c7e86SViresh Kumar unsafe { bindings::dev_pm_opp_put_opp_table(self.ptr) };
983d52c7e86SViresh Kumar
984d52c7e86SViresh Kumar #[cfg(CONFIG_OF)]
985d52c7e86SViresh Kumar {
986d52c7e86SViresh Kumar #[cfg(CONFIG_ENERGY_MODEL)]
987d52c7e86SViresh Kumar if self.em {
988d52c7e86SViresh Kumar self.of_unregister_em();
989d52c7e86SViresh Kumar }
990d52c7e86SViresh Kumar
991d52c7e86SViresh Kumar if self.of {
992d52c7e86SViresh Kumar self.remove_of();
993d52c7e86SViresh Kumar } else if let Some(cpumask) = self.cpus.take() {
994d52c7e86SViresh Kumar self.remove_of_cpumask(&cpumask);
995d52c7e86SViresh Kumar }
996d52c7e86SViresh Kumar }
997d52c7e86SViresh Kumar }
998d52c7e86SViresh Kumar }
999d52c7e86SViresh Kumar
10008f835497SViresh Kumar /// A reference-counted Operating performance point (OPP).
10018f835497SViresh Kumar ///
10028f835497SViresh Kumar /// Rust abstraction for the C `struct dev_pm_opp`.
10038f835497SViresh Kumar ///
10048f835497SViresh Kumar /// # Invariants
10058f835497SViresh Kumar ///
10068f835497SViresh Kumar /// The pointer stored in `Self` is non-null and valid for the lifetime of the [`OPP`].
10078f835497SViresh Kumar ///
10088f835497SViresh Kumar /// Instances of this type are reference-counted. The reference count is incremented by the
10098f835497SViresh Kumar /// `dev_pm_opp_get` function and decremented by `dev_pm_opp_put`. The Rust type `ARef<OPP>`
10108f835497SViresh Kumar /// represents a pointer that owns a reference count on the [`OPP`].
10118f835497SViresh Kumar ///
10128f835497SViresh Kumar /// A reference to the [`OPP`], &[`OPP`], isn't refcounted by the Rust code.
1013d52c7e86SViresh Kumar ///
1014d52c7e86SViresh Kumar /// ## Examples
1015d52c7e86SViresh Kumar ///
1016d52c7e86SViresh Kumar /// The following example demonstrates how to get [`OPP`] corresponding to a frequency value and
1017d52c7e86SViresh Kumar /// configure the device with it.
1018d52c7e86SViresh Kumar ///
1019d52c7e86SViresh Kumar /// ```
1020d52c7e86SViresh Kumar /// use kernel::clk::Hertz;
1021d52c7e86SViresh Kumar /// use kernel::error::Result;
1022d52c7e86SViresh Kumar /// use kernel::opp::{SearchType, Table};
1023d52c7e86SViresh Kumar ///
1024d52c7e86SViresh Kumar /// fn configure_opp(table: &Table, freq: Hertz) -> Result {
1025d52c7e86SViresh Kumar /// let opp = table.opp_from_freq(freq, Some(true), None, SearchType::Exact)?;
1026d52c7e86SViresh Kumar ///
1027d52c7e86SViresh Kumar /// if opp.freq(None) != freq {
1028d52c7e86SViresh Kumar /// return Err(EINVAL);
1029d52c7e86SViresh Kumar /// }
1030d52c7e86SViresh Kumar ///
1031d52c7e86SViresh Kumar /// table.set_opp(&opp)
1032d52c7e86SViresh Kumar /// }
1033d52c7e86SViresh Kumar /// ```
10348f835497SViresh Kumar #[repr(transparent)]
10358f835497SViresh Kumar pub struct OPP(Opaque<bindings::dev_pm_opp>);
10368f835497SViresh Kumar
10378f835497SViresh Kumar /// SAFETY: It is okay to send the ownership of [`OPP`] across thread boundaries.
10388f835497SViresh Kumar unsafe impl Send for OPP {}
10398f835497SViresh Kumar
10408f835497SViresh Kumar /// SAFETY: It is okay to access [`OPP`] through shared references from other threads because we're
10418f835497SViresh Kumar /// either accessing properties that don't change or that are properly synchronised by C code.
10428f835497SViresh Kumar unsafe impl Sync for OPP {}
10438f835497SViresh Kumar
10448f835497SViresh Kumar /// SAFETY: The type invariants guarantee that [`OPP`] is always refcounted.
10458f835497SViresh Kumar unsafe impl AlwaysRefCounted for OPP {
inc_ref(&self)10468f835497SViresh Kumar fn inc_ref(&self) {
10478f835497SViresh Kumar // SAFETY: The existence of a shared reference means that the refcount is nonzero.
10488f835497SViresh Kumar unsafe { bindings::dev_pm_opp_get(self.0.get()) };
10498f835497SViresh Kumar }
10508f835497SViresh Kumar
dec_ref(obj: ptr::NonNull<Self>)10518f835497SViresh Kumar unsafe fn dec_ref(obj: ptr::NonNull<Self>) {
10528f835497SViresh Kumar // SAFETY: The safety requirements guarantee that the refcount is nonzero.
10538f835497SViresh Kumar unsafe { bindings::dev_pm_opp_put(obj.cast().as_ptr()) }
10548f835497SViresh Kumar }
10558f835497SViresh Kumar }
10568f835497SViresh Kumar
10578f835497SViresh Kumar impl OPP {
10588f835497SViresh Kumar /// Creates an owned reference to a [`OPP`] from a valid pointer.
10598f835497SViresh Kumar ///
10608f835497SViresh Kumar /// The refcount is incremented by the C code and will be decremented by `dec_ref` when the
10618f835497SViresh Kumar /// [`ARef`] object is dropped.
10628f835497SViresh Kumar ///
10638f835497SViresh Kumar /// # Safety
10648f835497SViresh Kumar ///
10658f835497SViresh Kumar /// The caller must ensure that `ptr` is valid and the refcount of the [`OPP`] is incremented.
10668f835497SViresh Kumar /// The caller must also ensure that it doesn't explicitly drop the refcount of the [`OPP`], as
10678f835497SViresh Kumar /// the returned [`ARef`] object takes over the refcount increment on the underlying object and
10688f835497SViresh Kumar /// the same will be dropped along with it.
from_raw_opp_owned(ptr: *mut bindings::dev_pm_opp) -> Result<ARef<Self>>10698f835497SViresh Kumar pub unsafe fn from_raw_opp_owned(ptr: *mut bindings::dev_pm_opp) -> Result<ARef<Self>> {
10708f835497SViresh Kumar let ptr = ptr::NonNull::new(ptr).ok_or(ENODEV)?;
10718f835497SViresh Kumar
10728f835497SViresh Kumar // SAFETY: The safety requirements guarantee the validity of the pointer.
10738f835497SViresh Kumar //
10748f835497SViresh Kumar // INVARIANT: The reference-count is decremented when [`OPP`] goes out of scope.
10758f835497SViresh Kumar Ok(unsafe { ARef::from_raw(ptr.cast()) })
10768f835497SViresh Kumar }
10778f835497SViresh Kumar
10788f835497SViresh Kumar /// Creates a reference to a [`OPP`] from a valid pointer.
10798f835497SViresh Kumar ///
10808f835497SViresh Kumar /// The refcount is not updated by the Rust API unless the returned reference is converted to
10818f835497SViresh Kumar /// an [`ARef`] object.
10828f835497SViresh Kumar ///
10838f835497SViresh Kumar /// # Safety
10848f835497SViresh Kumar ///
10858f835497SViresh Kumar /// The caller must ensure that `ptr` is valid and remains valid for the duration of `'a`.
10868f835497SViresh Kumar #[inline]
from_raw_opp<'a>(ptr: *mut bindings::dev_pm_opp) -> Result<&'a Self>10878f835497SViresh Kumar pub unsafe fn from_raw_opp<'a>(ptr: *mut bindings::dev_pm_opp) -> Result<&'a Self> {
10888f835497SViresh Kumar // SAFETY: The caller guarantees that the pointer is not dangling and stays valid for the
10898f835497SViresh Kumar // duration of 'a. The cast is okay because [`OPP`] is `repr(transparent)`.
10908f835497SViresh Kumar Ok(unsafe { &*ptr.cast() })
10918f835497SViresh Kumar }
10928f835497SViresh Kumar
10938f835497SViresh Kumar #[inline]
as_raw(&self) -> *mut bindings::dev_pm_opp10948f835497SViresh Kumar fn as_raw(&self) -> *mut bindings::dev_pm_opp {
10958f835497SViresh Kumar self.0.get()
10968f835497SViresh Kumar }
10978f835497SViresh Kumar
10988f835497SViresh Kumar /// Returns the frequency of an [`OPP`].
freq(&self, index: Option<u32>) -> Hertz10998f835497SViresh Kumar pub fn freq(&self, index: Option<u32>) -> Hertz {
11008f835497SViresh Kumar let index = index.unwrap_or(0);
11018f835497SViresh Kumar
11028f835497SViresh Kumar // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
11038f835497SViresh Kumar // use it.
11048f835497SViresh Kumar Hertz(unsafe { bindings::dev_pm_opp_get_freq_indexed(self.as_raw(), index) })
11058f835497SViresh Kumar }
11068f835497SViresh Kumar
11078f835497SViresh Kumar /// Returns the voltage of an [`OPP`].
11088f835497SViresh Kumar #[inline]
voltage(&self) -> MicroVolt11098f835497SViresh Kumar pub fn voltage(&self) -> MicroVolt {
11108f835497SViresh Kumar // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
11118f835497SViresh Kumar // use it.
11128f835497SViresh Kumar MicroVolt(unsafe { bindings::dev_pm_opp_get_voltage(self.as_raw()) })
11138f835497SViresh Kumar }
11148f835497SViresh Kumar
11158f835497SViresh Kumar /// Returns the level of an [`OPP`].
11168f835497SViresh Kumar #[inline]
level(&self) -> u3211178f835497SViresh Kumar pub fn level(&self) -> u32 {
11188f835497SViresh Kumar // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
11198f835497SViresh Kumar // use it.
11208f835497SViresh Kumar unsafe { bindings::dev_pm_opp_get_level(self.as_raw()) }
11218f835497SViresh Kumar }
11228f835497SViresh Kumar
11238f835497SViresh Kumar /// Returns the power of an [`OPP`].
11248f835497SViresh Kumar #[inline]
power(&self) -> MicroWatt11258f835497SViresh Kumar pub fn power(&self) -> MicroWatt {
11268f835497SViresh Kumar // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
11278f835497SViresh Kumar // use it.
11288f835497SViresh Kumar MicroWatt(unsafe { bindings::dev_pm_opp_get_power(self.as_raw()) })
11298f835497SViresh Kumar }
11308f835497SViresh Kumar
11318f835497SViresh Kumar /// Returns the required pstate of an [`OPP`].
11328f835497SViresh Kumar #[inline]
required_pstate(&self, index: u32) -> u3211338f835497SViresh Kumar pub fn required_pstate(&self, index: u32) -> u32 {
11348f835497SViresh Kumar // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
11358f835497SViresh Kumar // use it.
11368f835497SViresh Kumar unsafe { bindings::dev_pm_opp_get_required_pstate(self.as_raw(), index) }
11378f835497SViresh Kumar }
11388f835497SViresh Kumar
11398f835497SViresh Kumar /// Returns true if the [`OPP`] is turbo.
11408f835497SViresh Kumar #[inline]
is_turbo(&self) -> bool11418f835497SViresh Kumar pub fn is_turbo(&self) -> bool {
11428f835497SViresh Kumar // SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
11438f835497SViresh Kumar // use it.
11448f835497SViresh Kumar unsafe { bindings::dev_pm_opp_is_turbo(self.as_raw()) }
11458f835497SViresh Kumar }
11468f835497SViresh Kumar }
1147