1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// List of power levels.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PowerLevels<T> {
    /// List of possible levels.
    pub levels: Vec<T>,
    /// The currently active level.
    pub active: Option<usize>,
}

impl<T> PowerLevels<T> {
    /// Gets the currently active level value.
    pub fn active_level(&self) -> Option<&T> {
        self.active.and_then(|active| self.levels.get(active))
    }
}

macro_rules! impl_get_clocks_levels {
    ($name:ident, $level:expr, $out:ty) => {
        /// Gets clocks levels.
        pub fn $name(&self) -> Result<PowerLevels<$out>> {
            self.get_clock_levels($level)
        }
    };
}

/// Type of a power level.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
pub enum PowerLevelKind {
    CoreClock,
    MemoryClock,
    SOCClock,
    FabricClock,
    DCEFClock,
    PcieSpeed,
}

impl PowerLevelKind {
    /// Gets the filename of a given power level kind.
    pub fn filename(&self) -> &str {
        use PowerLevelKind::*;
        match self {
            CoreClock => "pp_dpm_sclk",
            MemoryClock => "pp_dpm_mclk",
            SOCClock => "pp_dpm_socclk",
            FabricClock => "pp_dpm_fclk",
            DCEFClock => "pp_dpm_dcefclk",
            PcieSpeed => "pp_dpm_pcie",
        }
    }

    /// Suffix of the power level value
    pub fn value_suffix(&self) -> Option<&str> {
        use PowerLevelKind::*;
        match self {
            CoreClock | MemoryClock | SOCClock | FabricClock | DCEFClock => Some("mhz"),
            PcieSpeed => None,
        }
    }
}